mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 14:47:13 -04:00
chore: replace str with uuid
This commit is contained in:
parent
e870481ef9
commit
0975f6c8c0
100 changed files with 1557 additions and 1346 deletions
88
frontend/rust-lib/Cargo.lock
generated
88
frontend/rust-lib/Cargo.lock
generated
|
@ -496,7 +496,7 @@ checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
|||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
@ -516,16 +516,16 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "appflowy-ai-client"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"futures",
|
||||
"pin-project",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"thiserror 1.0.64",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1137,7 +1137,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"again",
|
||||
"anyhow",
|
||||
|
@ -1192,7 +1192,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "client-api-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"collab-entity",
|
||||
"collab-rt-entity",
|
||||
|
@ -1205,7 +1205,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
|
@ -1248,7 +1248,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=80d1c6147d1139289c2eaadab40557cc86c0f4b6#80d1c6147d1139289c2eaadab40557cc86c0f4b6"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4a0e2cc07f50f17d1b6605c579e622a431e94998#4a0e2cc07f50f17d1b6605c579e622a431e94998"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
@ -1273,7 +1273,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=80d1c6147d1139289c2eaadab40557cc86c0f4b6#80d1c6147d1139289c2eaadab40557cc86c0f4b6"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4a0e2cc07f50f17d1b6605c579e622a431e94998#4a0e2cc07f50f17d1b6605c579e622a431e94998"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1313,7 +1313,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=80d1c6147d1139289c2eaadab40557cc86c0f4b6#80d1c6147d1139289c2eaadab40557cc86c0f4b6"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4a0e2cc07f50f17d1b6605c579e622a431e94998#4a0e2cc07f50f17d1b6605c579e622a431e94998"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
@ -1334,7 +1334,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=80d1c6147d1139289c2eaadab40557cc86c0f4b6#80d1c6147d1139289c2eaadab40557cc86c0f4b6"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4a0e2cc07f50f17d1b6605c579e622a431e94998#4a0e2cc07f50f17d1b6605c579e622a431e94998"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
@ -1354,7 +1354,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=80d1c6147d1139289c2eaadab40557cc86c0f4b6#80d1c6147d1139289c2eaadab40557cc86c0f4b6"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4a0e2cc07f50f17d1b6605c579e622a431e94998#4a0e2cc07f50f17d1b6605c579e622a431e94998"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
@ -1376,7 +1376,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-importer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=80d1c6147d1139289c2eaadab40557cc86c0f4b6#80d1c6147d1139289c2eaadab40557cc86c0f4b6"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4a0e2cc07f50f17d1b6605c579e622a431e94998#4a0e2cc07f50f17d1b6605c579e622a431e94998"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
|
@ -1418,7 +1418,6 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"async-trait",
|
||||
"collab",
|
||||
"collab-database",
|
||||
"collab-document",
|
||||
|
@ -1429,18 +1428,18 @@ dependencies = [
|
|||
"diesel",
|
||||
"flowy-error",
|
||||
"flowy-sqlite",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=80d1c6147d1139289c2eaadab40557cc86c0f4b6#80d1c6147d1139289c2eaadab40557cc86c0f4b6"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4a0e2cc07f50f17d1b6605c579e622a431e94998#4a0e2cc07f50f17d1b6605c579e622a431e94998"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
|
@ -1478,7 +1477,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-rt-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
@ -1500,7 +1499,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-rt-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1511,13 +1510,14 @@ dependencies = [
|
|||
"thiserror 1.0.64",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"yrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=80d1c6147d1139289c2eaadab40557cc86c0f4b6#80d1c6147d1139289c2eaadab40557cc86c0f4b6"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4a0e2cc07f50f17d1b6605c579e622a431e94998#4a0e2cc07f50f17d1b6605c579e622a431e94998"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
|
@ -1764,7 +1764,7 @@ dependencies = [
|
|||
"cssparser-macros",
|
||||
"dtoa-short",
|
||||
"itoa",
|
||||
"phf 0.11.2",
|
||||
"phf 0.8.0",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
|
@ -1947,7 +1947,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
|||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bytes",
|
||||
|
@ -2513,13 +2513,13 @@ dependencies = [
|
|||
name = "flowy-ai-pub"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"client-api",
|
||||
"flowy-error",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2592,7 +2592,6 @@ dependencies = [
|
|||
"flowy-storage-pub",
|
||||
"flowy-user",
|
||||
"flowy-user-pub",
|
||||
"futures",
|
||||
"futures-core",
|
||||
"lib-dispatch",
|
||||
"lib-infra",
|
||||
|
@ -2606,19 +2605,18 @@ dependencies = [
|
|||
"tokio-stream",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-database-pub"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"client-api",
|
||||
"collab",
|
||||
"collab-entity",
|
||||
"flowy-error",
|
||||
"lib-infra",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2667,6 +2665,7 @@ dependencies = [
|
|||
"tokio-util",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
"validator 0.18.1",
|
||||
]
|
||||
|
||||
|
@ -2744,11 +2743,11 @@ dependencies = [
|
|||
name = "flowy-document-pub"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
"collab-document",
|
||||
"flowy-error",
|
||||
"lib-infra",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2778,6 +2777,7 @@ dependencies = [
|
|||
"thiserror 1.0.64",
|
||||
"tokio",
|
||||
"url",
|
||||
"uuid",
|
||||
"validator 0.18.1",
|
||||
]
|
||||
|
||||
|
@ -2864,16 +2864,12 @@ dependencies = [
|
|||
"bytes",
|
||||
"collab",
|
||||
"collab-folder",
|
||||
"diesel",
|
||||
"diesel_derives",
|
||||
"diesel_migrations",
|
||||
"flowy-codegen",
|
||||
"flowy-derive",
|
||||
"flowy-error",
|
||||
"flowy-folder",
|
||||
"flowy-notification",
|
||||
"flowy-search-pub",
|
||||
"flowy-sqlite",
|
||||
"flowy-user",
|
||||
"futures",
|
||||
"lib-dispatch",
|
||||
|
@ -2887,7 +2883,7 @@ dependencies = [
|
|||
"tempfile",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"validator 0.18.1",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2898,8 +2894,8 @@ dependencies = [
|
|||
"collab",
|
||||
"collab-folder",
|
||||
"flowy-error",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2991,7 +2987,6 @@ name = "flowy-storage"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"allo-isolate",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"chrono",
|
||||
|
@ -3003,8 +2998,6 @@ dependencies = [
|
|||
"flowy-notification",
|
||||
"flowy-sqlite",
|
||||
"flowy-storage-pub",
|
||||
"futures-util",
|
||||
"fxhash",
|
||||
"lib-dispatch",
|
||||
"lib-infra",
|
||||
"mime_guess",
|
||||
|
@ -3032,9 +3025,8 @@ dependencies = [
|
|||
"mime",
|
||||
"mime_guess",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3432,7 +3424,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"getrandom 0.2.10",
|
||||
|
@ -3447,7 +3439,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"app-error",
|
||||
"jsonwebtoken",
|
||||
|
@ -4068,7 +4060,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
@ -5181,7 +5173,7 @@ version = "0.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||
dependencies = [
|
||||
"phf_macros 0.8.0",
|
||||
"phf_macros",
|
||||
"phf_shared 0.8.0",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
@ -5201,7 +5193,6 @@ version = "0.11.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_macros 0.11.3",
|
||||
"phf_shared 0.11.2",
|
||||
]
|
||||
|
||||
|
@ -5269,19 +5260,6 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
|
||||
dependencies = [
|
||||
"phf_generator 0.11.2",
|
||||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.8.0"
|
||||
|
@ -6782,7 +6760,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "shared-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=f7288f46c27dc8e3c7829cda1b70b61118e88336#f7288f46c27dc8e3c7829cda1b70b61118e88336"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e#2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
|
|
|
@ -103,8 +103,8 @@ dashmap = "6.0.1"
|
|||
# Run the script.add_workspace_members:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "f7288f46c27dc8e3c7829cda1b70b61118e88336" }
|
||||
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "f7288f46c27dc8e3c7829cda1b70b61118e88336" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e" }
|
||||
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "2922db6801ca23c5fd6fe8b4958f03bc54dbcb7e" }
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
|
@ -139,14 +139,14 @@ rocksdb = { git = "https://github.com/rust-rocksdb/rust-rocksdb", rev = "1710120
|
|||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "80d1c6147d1139289c2eaadab40557cc86c0f4b6" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "80d1c6147d1139289c2eaadab40557cc86c0f4b6" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "80d1c6147d1139289c2eaadab40557cc86c0f4b6" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "80d1c6147d1139289c2eaadab40557cc86c0f4b6" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "80d1c6147d1139289c2eaadab40557cc86c0f4b6" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "80d1c6147d1139289c2eaadab40557cc86c0f4b6" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "80d1c6147d1139289c2eaadab40557cc86c0f4b6" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "80d1c6147d1139289c2eaadab40557cc86c0f4b6" }
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4a0e2cc07f50f17d1b6605c579e622a431e94998" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4a0e2cc07f50f17d1b6605c579e622a431e94998" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4a0e2cc07f50f17d1b6605c579e622a431e94998" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4a0e2cc07f50f17d1b6605c579e622a431e94998" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4a0e2cc07f50f17d1b6605c579e622a431e94998" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4a0e2cc07f50f17d1b6605c579e622a431e94998" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4a0e2cc07f50f17d1b6605c579e622a431e94998" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4a0e2cc07f50f17d1b6605c579e622a431e94998" }
|
||||
|
||||
# Working directory: frontend
|
||||
# To update the commit ID, run:
|
||||
|
|
|
@ -19,14 +19,13 @@ serde.workspace = true
|
|||
serde_json.workspace = true
|
||||
anyhow.workspace = true
|
||||
tracing.workspace = true
|
||||
async-trait.workspace = true
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
lib-infra = { workspace = true }
|
||||
futures = "0.3.31"
|
||||
arc-swap = "1.7"
|
||||
flowy-sqlite = { workspace = true }
|
||||
diesel.workspace = true
|
||||
flowy-error.workspace = true
|
||||
uuid.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::borrow::BorrowMut;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use crate::CollabKVDB;
|
||||
|
@ -33,8 +34,10 @@ use collab_plugins::local_storage::kv::KVTransactionDB;
|
|||
use collab_plugins::local_storage::CollabPersistenceConfig;
|
||||
use collab_user::core::{UserAwareness, UserAwarenessNotifier};
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::{if_native, if_wasm};
|
||||
use tracing::{error, instrument, trace, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CollabPluginProviderType {
|
||||
|
@ -66,8 +69,8 @@ impl Display for CollabPluginProviderContext {
|
|||
}
|
||||
|
||||
pub trait WorkspaceCollabIntegrate: Send + Sync {
|
||||
fn workspace_id(&self) -> Result<String, Error>;
|
||||
fn device_id(&self) -> Result<String, Error>;
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError>;
|
||||
fn device_id(&self) -> Result<String, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct AppFlowyCollabBuilder {
|
||||
|
@ -119,15 +122,15 @@ impl AppFlowyCollabBuilder {
|
|||
|
||||
pub fn collab_object(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
) -> Result<CollabObject, Error> {
|
||||
// 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 {
|
||||
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,
|
||||
|
@ -140,7 +143,7 @@ impl AppFlowyCollabBuilder {
|
|||
uid,
|
||||
object_id.to_string(),
|
||||
collab_type,
|
||||
workspace_id,
|
||||
workspace_id.to_string(),
|
||||
device_id,
|
||||
))
|
||||
}
|
||||
|
@ -399,11 +402,11 @@ impl CollabBuilderConfig {
|
|||
pub struct CollabPersistenceImpl {
|
||||
pub db: Weak<CollabKVDB>,
|
||||
pub uid: i64,
|
||||
pub workspace_id: String,
|
||||
pub workspace_id: Uuid,
|
||||
}
|
||||
|
||||
impl CollabPersistenceImpl {
|
||||
pub fn new(db: Weak<CollabKVDB>, uid: i64, workspace_id: String) -> Self {
|
||||
pub fn new(db: Weak<CollabKVDB>, uid: i64, workspace_id: Uuid) -> Self {
|
||||
Self {
|
||||
db,
|
||||
uid,
|
||||
|
@ -423,7 +426,8 @@ impl CollabPersistence for CollabPersistenceImpl {
|
|||
.upgrade()
|
||||
.ok_or_else(|| CollabError::Internal(anyhow!("collab_db is dropped")))?;
|
||||
|
||||
let object_id = collab.object_id().to_string();
|
||||
let object_id =
|
||||
Uuid::from_str(collab.object_id()).map_err(|v| CollabError::Internal(v.into()))?;
|
||||
let rocksdb_read = collab_db.read_txn();
|
||||
|
||||
if rocksdb_read.is_exist(self.uid, &self.workspace_id, &object_id) {
|
||||
|
@ -461,7 +465,7 @@ impl CollabPersistence for CollabPersistenceImpl {
|
|||
write_txn
|
||||
.flush_doc(
|
||||
self.uid,
|
||||
self.workspace_id.as_str(),
|
||||
self.workspace_id.to_string().as_str(),
|
||||
object_id,
|
||||
encoded_collab.state_vector.to_vec(),
|
||||
encoded_collab.doc_state.to_vec(),
|
||||
|
|
|
@ -7,6 +7,8 @@ use flowy_sqlite::{
|
|||
DBConnection, ExpressionMethods, Identifiable, Insertable, Queryable,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Queryable, Insertable, Identifiable)]
|
||||
#[diesel(table_name = af_collab_metadata)]
|
||||
|
@ -43,13 +45,18 @@ pub fn batch_insert_collab_metadata(
|
|||
|
||||
pub fn batch_select_collab_metadata(
|
||||
mut conn: DBConnection,
|
||||
object_ids: &[String],
|
||||
) -> FlowyResult<HashMap<String, AFCollabMetadata>> {
|
||||
object_ids: &[Uuid],
|
||||
) -> FlowyResult<HashMap<Uuid, AFCollabMetadata>> {
|
||||
let object_ids = object_ids
|
||||
.iter()
|
||||
.map(|id| id.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let metadata = dsl::af_collab_metadata
|
||||
.filter(af_collab_metadata::object_id.eq_any(object_ids))
|
||||
.filter(af_collab_metadata::object_id.eq_any(&object_ids))
|
||||
.load::<AFCollabMetadata>(&mut conn)?
|
||||
.into_iter()
|
||||
.map(|m| (m.object_id.clone(), m))
|
||||
.flat_map(|m| Uuid::from_str(&m.object_id).and_then(|v| Ok((v, m))))
|
||||
.collect();
|
||||
Ok(metadata)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use collab::entity::EncodedCollab;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use flowy_document::entities::*;
|
||||
use flowy_document::event_map::DocumentEvent;
|
||||
use flowy_document::parser::parser_entities::{
|
||||
|
@ -11,6 +9,8 @@ use flowy_document::parser::parser_entities::{
|
|||
};
|
||||
use flowy_folder::entities::{CreateViewPayloadPB, ViewLayoutPB, ViewPB};
|
||||
use flowy_folder::event_map::FolderEvent;
|
||||
use serde_json::Value;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::document::utils::{gen_delta_str, gen_id, gen_text_block_data};
|
||||
use crate::event_builder::EventBuilder;
|
||||
|
@ -37,7 +37,7 @@ impl DocumentEventTest {
|
|||
Self { event_test: core }
|
||||
}
|
||||
|
||||
pub async fn get_encoded_v1(&self, doc_id: &str) -> EncodedCollab {
|
||||
pub async fn get_encoded_v1(&self, doc_id: &Uuid) -> EncodedCollab {
|
||||
let doc = self
|
||||
.event_test
|
||||
.appflowy_core
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use flowy_folder::view_operation::{GatherEncodedCollab, ViewData};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_folder::{FolderData, View};
|
||||
|
@ -16,6 +17,7 @@ use flowy_user::entities::{
|
|||
use flowy_user::errors::FlowyError;
|
||||
use flowy_user::event_map::UserEvent;
|
||||
use flowy_user_pub::entities::Role;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::event_builder::EventBuilder;
|
||||
use crate::EventIntegrationTest;
|
||||
|
@ -123,10 +125,10 @@ impl EventIntegrationTest {
|
|||
let create_view_params = views
|
||||
.into_iter()
|
||||
.map(|view| CreateViewParams {
|
||||
parent_view_id: view.parent_view_id,
|
||||
parent_view_id: Uuid::from_str(&view.parent_view_id).unwrap(),
|
||||
name: view.name,
|
||||
layout: view.layout.into(),
|
||||
view_id: view.id,
|
||||
view_id: Uuid::from_str(&view.id).unwrap(),
|
||||
initial_data: ViewData::Empty,
|
||||
meta: Default::default(),
|
||||
set_as_current: false,
|
||||
|
@ -195,9 +197,10 @@ impl EventIntegrationTest {
|
|||
view_id: &str,
|
||||
layout: ViewLayout,
|
||||
) -> GatherEncodedCollab {
|
||||
let view_id = Uuid::from_str(view_id).unwrap();
|
||||
self
|
||||
.folder_manager
|
||||
.gather_publish_encode_collab(view_id, &layout)
|
||||
.gather_publish_encode_collab(&view_id, &layout)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::user_event::TestNotificationSender;
|
||||
use collab::core::collab::DataSource;
|
||||
use collab::core::origin::CollabOrigin;
|
||||
use collab::preclude::Collab;
|
||||
|
@ -15,14 +16,14 @@ use nanoid::nanoid;
|
|||
use semver::Version;
|
||||
use std::env::temp_dir;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::select;
|
||||
use tokio::task::LocalSet;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::user_event::TestNotificationSender;
|
||||
use uuid::Uuid;
|
||||
|
||||
mod chat_event;
|
||||
pub mod database_event;
|
||||
|
@ -145,10 +146,16 @@ impl EventIntegrationTest {
|
|||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let server = self.server_provider.get_server().unwrap();
|
||||
let workspace_id = self.get_current_workspace().await.id;
|
||||
let oid = Uuid::from_str(oid).unwrap();
|
||||
let uid = self.get_user_profile().await?.id;
|
||||
let doc_state = server
|
||||
.folder_service()
|
||||
.get_folder_doc_state(&workspace_id, uid, collab_type, oid)
|
||||
.get_folder_doc_state(
|
||||
&Uuid::from_str(&workspace_id).unwrap(),
|
||||
uid,
|
||||
collab_type,
|
||||
&oid,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(doc_state)
|
||||
|
|
|
@ -3,10 +3,12 @@ use event_integration_test::user_event::use_localhost_af_cloud;
|
|||
use event_integration_test::EventIntegrationTest;
|
||||
use flowy_ai::entities::ChatMessageListPB;
|
||||
use flowy_ai::notification::ChatNotification;
|
||||
use std::str::FromStr;
|
||||
|
||||
use flowy_ai_pub::cloud::ChatMessageType;
|
||||
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_create_chat_message_test() {
|
||||
|
@ -21,8 +23,8 @@ async fn af_cloud_create_chat_message_test() {
|
|||
for i in 0..10 {
|
||||
let _ = chat_service
|
||||
.create_question(
|
||||
¤t_workspace.id,
|
||||
&chat_id,
|
||||
&Uuid::from_str(¤t_workspace.id).unwrap(),
|
||||
&Uuid::from_str(&chat_id).unwrap(),
|
||||
&format!("hello world {}", i),
|
||||
ChatMessageType::System,
|
||||
&[],
|
||||
|
@ -77,8 +79,8 @@ async fn af_cloud_load_remote_system_message_test() {
|
|||
for i in 0..10 {
|
||||
let _ = chat_service
|
||||
.create_question(
|
||||
¤t_workspace.id,
|
||||
&chat_id,
|
||||
&Uuid::from_str(¤t_workspace.id).unwrap(),
|
||||
&Uuid::from_str(&chat_id).unwrap(),
|
||||
&format!("hello server {}", i),
|
||||
ChatMessageType::System,
|
||||
&[],
|
||||
|
|
|
@ -8,6 +8,8 @@ use flowy_document::parser::parser_entities::{
|
|||
};
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_document_event_test() {
|
||||
|
@ -101,8 +103,8 @@ async fn document_size_test() {
|
|||
let s = generate_random_string(string_size);
|
||||
test.insert_index(&view.id, &s, 1, None).await;
|
||||
}
|
||||
|
||||
let encoded_v1 = test.get_encoded_v1(&view.id).await;
|
||||
let view_id = Uuid::from_str(&view.id).unwrap();
|
||||
let encoded_v1 = test.get_encoded_v1(&view_id).await;
|
||||
if encoded_v1.doc_state.len() > max_size {
|
||||
panic!(
|
||||
"The document size is too large. {}",
|
||||
|
|
|
@ -9,7 +9,7 @@ edition = "2021"
|
|||
lib-infra = { workspace = true }
|
||||
flowy-error = { workspace = true }
|
||||
client-api = { workspace = true }
|
||||
bytes.workspace = true
|
||||
futures.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
serde.workspace = true
|
||||
uuid.workspace = true
|
|
@ -19,6 +19,7 @@ use serde::{Deserialize, Serialize};
|
|||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub type ChatMessageStream = BoxStream<'static, Result<ChatMessage, AppResponseError>>;
|
||||
pub type StreamAnswer = BoxStream<'static, Result<QuestionStreamValue, FlowyError>>;
|
||||
|
@ -81,15 +82,15 @@ pub trait ChatCloudService: Send + Sync + 'static {
|
|||
async fn create_chat(
|
||||
&self,
|
||||
uid: &i64,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
rag_ids: Vec<String>,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn create_question(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
message_type: ChatMessageType,
|
||||
metadata: &[ChatMessageMetadata],
|
||||
|
@ -97,8 +98,8 @@ pub trait ChatCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn create_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
question_id: i64,
|
||||
metadata: Option<serde_json::Value>,
|
||||
|
@ -106,8 +107,8 @@ pub trait ChatCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn stream_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
format: ResponseFormat,
|
||||
ai_model: Option<AIModel>,
|
||||
|
@ -115,68 +116,68 @@ pub trait ChatCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn get_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
question_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError>;
|
||||
|
||||
async fn get_chat_messages(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
offset: MessageCursor,
|
||||
limit: u64,
|
||||
) -> Result<RepeatedChatMessage, FlowyError>;
|
||||
|
||||
async fn get_question_from_answer_id(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
answer_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError>;
|
||||
|
||||
async fn get_related_message(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
) -> Result<RepeatedRelatedQuestion, FlowyError>;
|
||||
|
||||
async fn stream_complete(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
params: CompleteTextParams,
|
||||
ai_model: Option<AIModel>,
|
||||
) -> Result<StreamComplete, FlowyError>;
|
||||
|
||||
async fn embed_file(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
file_path: &Path,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
metadata: Option<HashMap<String, Value>>,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn get_local_ai_config(&self, workspace_id: &str) -> Result<LocalAIConfig, FlowyError>;
|
||||
async fn get_local_ai_config(&self, workspace_id: &Uuid) -> Result<LocalAIConfig, FlowyError>;
|
||||
|
||||
async fn get_workspace_plan(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<SubscriptionPlan>, FlowyError>;
|
||||
|
||||
async fn get_chat_settings(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<ChatSettings, FlowyError>;
|
||||
|
||||
async fn update_chat_settings(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
params: UpdateChatParams,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn get_available_models(&self, workspace_id: &str) -> Result<ModelList, FlowyError>;
|
||||
async fn get_workspace_default_model(&self, workspace_id: &str) -> Result<String, FlowyError>;
|
||||
async fn get_available_models(&self, workspace_id: &Uuid) -> Result<ModelList, FlowyError>;
|
||||
async fn get_workspace_default_model(&self, workspace_id: &Uuid) -> Result<String, FlowyError>;
|
||||
}
|
||||
|
|
|
@ -27,14 +27,16 @@ use flowy_storage_pub::storage::StorageService;
|
|||
use lib_infra::async_trait::async_trait;
|
||||
use lib_infra::util::timestamp;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{error, info, instrument, trace};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub trait AIUserService: Send + Sync + 'static {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn device_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError>;
|
||||
fn sqlite_connection(&self, uid: i64) -> Result<DBConnection, FlowyError>;
|
||||
fn application_root_dir(&self) -> Result<PathBuf, FlowyError>;
|
||||
}
|
||||
|
@ -44,18 +46,18 @@ pub trait AIUserService: Send + Sync + 'static {
|
|||
pub trait AIExternalService: Send + Sync + 'static {
|
||||
async fn query_chat_rag_ids(
|
||||
&self,
|
||||
parent_view_id: &str,
|
||||
chat_id: &str,
|
||||
) -> Result<Vec<String>, FlowyError>;
|
||||
parent_view_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<Vec<Uuid>, FlowyError>;
|
||||
|
||||
async fn sync_rag_documents(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
rag_ids: Vec<String>,
|
||||
rag_metadata_map: HashMap<String, AFCollabMetadata>,
|
||||
workspace_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
rag_metadata_map: HashMap<Uuid, AFCollabMetadata>,
|
||||
) -> Result<Vec<AFCollabMetadata>, FlowyError>;
|
||||
|
||||
async fn notify_did_send_message(&self, chat_id: &str, message: &str) -> Result<(), FlowyError>;
|
||||
async fn notify_did_send_message(&self, chat_id: &Uuid, message: &str) -> Result<(), FlowyError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -70,7 +72,7 @@ pub struct AIManager {
|
|||
pub cloud_service_wm: Arc<AICloudServiceMiddleware>,
|
||||
pub user_service: Arc<dyn AIUserService>,
|
||||
pub external_service: Arc<dyn AIExternalService>,
|
||||
chats: Arc<DashMap<String, Arc<Chat>>>,
|
||||
chats: Arc<DashMap<Uuid, Arc<Chat>>>,
|
||||
pub local_ai: Arc<LocalAIController>,
|
||||
pub store_preferences: Arc<KVStorePreferences>,
|
||||
server_models: Arc<RwLock<ServerModelsCache>>,
|
||||
|
@ -132,11 +134,11 @@ impl AIManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn open_chat(&self, chat_id: &str) -> Result<(), FlowyError> {
|
||||
self.chats.entry(chat_id.to_string()).or_insert_with(|| {
|
||||
pub async fn open_chat(&self, chat_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self.chats.entry(chat_id.clone()).or_insert_with(|| {
|
||||
Arc::new(Chat::new(
|
||||
self.user_service.user_id().unwrap(),
|
||||
chat_id.to_string(),
|
||||
chat_id.clone(),
|
||||
self.user_service.clone(),
|
||||
self.cloud_service_wm.clone(),
|
||||
))
|
||||
|
@ -150,7 +152,7 @@ impl AIManager {
|
|||
let cloud_service_wm = self.cloud_service_wm.clone();
|
||||
let store_preferences = self.store_preferences.clone();
|
||||
let external_service = self.external_service.clone();
|
||||
let chat_id = chat_id.to_string();
|
||||
let chat_id = chat_id.clone();
|
||||
tokio::spawn(async move {
|
||||
match refresh_chat_setting(
|
||||
&user_service,
|
||||
|
@ -161,7 +163,12 @@ impl AIManager {
|
|||
.await
|
||||
{
|
||||
Ok(settings) => {
|
||||
let _ = sync_chat_documents(user_service, external_service, settings.rag_ids).await;
|
||||
let rag_ids = settings
|
||||
.rag_ids
|
||||
.into_iter()
|
||||
.flat_map(|r| Uuid::from_str(&r).ok())
|
||||
.collect();
|
||||
let _ = sync_chat_documents(user_service, external_service, rag_ids).await;
|
||||
},
|
||||
Err(err) => {
|
||||
error!("failed to refresh chat settings: {}", err);
|
||||
|
@ -172,13 +179,13 @@ impl AIManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn close_chat(&self, chat_id: &str) -> Result<(), FlowyError> {
|
||||
pub async fn close_chat(&self, chat_id: &Uuid) -> Result<(), FlowyError> {
|
||||
trace!("close chat: {}", chat_id);
|
||||
self.local_ai.close_chat(chat_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_chat(&self, chat_id: &str) -> Result<(), FlowyError> {
|
||||
pub async fn delete_chat(&self, chat_id: &Uuid) -> Result<(), FlowyError> {
|
||||
if let Some((_, chat)) = self.chats.remove(chat_id) {
|
||||
chat.close();
|
||||
|
||||
|
@ -212,8 +219,8 @@ impl AIManager {
|
|||
pub async fn create_chat(
|
||||
&self,
|
||||
uid: &i64,
|
||||
parent_view_id: &str,
|
||||
chat_id: &str,
|
||||
parent_view_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<Arc<Chat>, FlowyError> {
|
||||
let workspace_id = self.user_service.workspace_id()?;
|
||||
let rag_ids = self
|
||||
|
@ -231,11 +238,11 @@ impl AIManager {
|
|||
|
||||
let chat = Arc::new(Chat::new(
|
||||
self.user_service.user_id()?,
|
||||
chat_id.to_string(),
|
||||
chat_id.clone(),
|
||||
self.user_service.clone(),
|
||||
self.cloud_service_wm.clone(),
|
||||
));
|
||||
self.chats.insert(chat_id.to_string(), chat.clone());
|
||||
self.chats.insert(chat_id.clone(), chat.clone());
|
||||
Ok(chat)
|
||||
}
|
||||
|
||||
|
@ -244,7 +251,7 @@ impl AIManager {
|
|||
params: StreamMessageParams,
|
||||
) -> Result<ChatMessagePB, FlowyError> {
|
||||
let chat = self.get_or_create_chat_instance(¶ms.chat_id).await?;
|
||||
let ai_model = self.get_active_model(¶ms.chat_id).await;
|
||||
let ai_model = self.get_active_model(¶ms.chat_id.to_string()).await;
|
||||
let question = chat.stream_chat_message(¶ms, ai_model).await?;
|
||||
let _ = self
|
||||
.external_service
|
||||
|
@ -255,7 +262,7 @@ impl AIManager {
|
|||
|
||||
pub async fn stream_regenerate_response(
|
||||
&self,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
answer_message_id: i64,
|
||||
answer_stream_port: i64,
|
||||
format: Option<PredefinedFormatPB>,
|
||||
|
@ -270,7 +277,7 @@ impl AIManager {
|
|||
|| {
|
||||
self
|
||||
.store_preferences
|
||||
.get_object::<AIModel>(&ai_available_models_key(chat_id))
|
||||
.get_object::<AIModel>(&ai_available_models_key(&chat_id.to_string()))
|
||||
},
|
||||
|model| Some(model.into()),
|
||||
);
|
||||
|
@ -520,17 +527,17 @@ impl AIManager {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn get_or_create_chat_instance(&self, chat_id: &str) -> Result<Arc<Chat>, FlowyError> {
|
||||
pub async fn get_or_create_chat_instance(&self, chat_id: &Uuid) -> Result<Arc<Chat>, FlowyError> {
|
||||
let chat = self.chats.get(chat_id).as_deref().cloned();
|
||||
match chat {
|
||||
None => {
|
||||
let chat = Arc::new(Chat::new(
|
||||
self.user_service.user_id()?,
|
||||
chat_id.to_string(),
|
||||
chat_id.clone(),
|
||||
self.user_service.clone(),
|
||||
self.cloud_service_wm.clone(),
|
||||
));
|
||||
self.chats.insert(chat_id.to_string(), chat.clone());
|
||||
self.chats.insert(chat_id.clone(), chat.clone());
|
||||
Ok(chat)
|
||||
},
|
||||
Some(chat) => Ok(chat),
|
||||
|
@ -554,7 +561,7 @@ impl AIManager {
|
|||
|
||||
pub async fn load_prev_chat_messages(
|
||||
&self,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
limit: i64,
|
||||
before_message_id: Option<i64>,
|
||||
) -> Result<ChatMessageListPB, FlowyError> {
|
||||
|
@ -567,7 +574,7 @@ impl AIManager {
|
|||
|
||||
pub async fn load_latest_chat_messages(
|
||||
&self,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
limit: i64,
|
||||
after_message_id: Option<i64>,
|
||||
) -> Result<ChatMessageListPB, FlowyError> {
|
||||
|
@ -580,7 +587,7 @@ impl AIManager {
|
|||
|
||||
pub async fn get_related_questions(
|
||||
&self,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
) -> Result<RepeatedRelatedQuestionPB, FlowyError> {
|
||||
let chat = self.get_or_create_chat_instance(chat_id).await?;
|
||||
|
@ -590,7 +597,7 @@ impl AIManager {
|
|||
|
||||
pub async fn generate_answer(
|
||||
&self,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
question_message_id: i64,
|
||||
) -> Result<ChatMessagePB, FlowyError> {
|
||||
let chat = self.get_or_create_chat_instance(chat_id).await?;
|
||||
|
@ -598,19 +605,19 @@ impl AIManager {
|
|||
Ok(resp)
|
||||
}
|
||||
|
||||
pub async fn stop_stream(&self, chat_id: &str) -> Result<(), FlowyError> {
|
||||
pub async fn stop_stream(&self, chat_id: &Uuid) -> Result<(), FlowyError> {
|
||||
let chat = self.get_or_create_chat_instance(chat_id).await?;
|
||||
chat.stop_stream_message().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn chat_with_file(&self, chat_id: &str, file_path: PathBuf) -> FlowyResult<()> {
|
||||
pub async fn chat_with_file(&self, chat_id: &Uuid, file_path: PathBuf) -> FlowyResult<()> {
|
||||
let chat = self.get_or_create_chat_instance(chat_id).await?;
|
||||
chat.index_file(file_path).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_rag_ids(&self, chat_id: &str) -> FlowyResult<Vec<String>> {
|
||||
pub async fn get_rag_ids(&self, chat_id: &Uuid) -> FlowyResult<Vec<String>> {
|
||||
if let Some(settings) = self
|
||||
.store_preferences
|
||||
.get_object::<ChatSettings>(&setting_store_key(chat_id))
|
||||
|
@ -628,7 +635,7 @@ impl AIManager {
|
|||
Ok(settings.rag_ids)
|
||||
}
|
||||
|
||||
pub async fn update_rag_ids(&self, chat_id: &str, rag_ids: Vec<String>) -> FlowyResult<()> {
|
||||
pub async fn update_rag_ids(&self, chat_id: &Uuid, rag_ids: Vec<String>) -> FlowyResult<()> {
|
||||
info!("[Chat] update chat:{} rag ids: {:?}", chat_id, rag_ids);
|
||||
let workspace_id = self.user_service.workspace_id()?;
|
||||
let update_setting = UpdateChatParams {
|
||||
|
@ -659,6 +666,10 @@ impl AIManager {
|
|||
|
||||
let user_service = self.user_service.clone();
|
||||
let external_service = self.external_service.clone();
|
||||
let rag_ids = rag_ids
|
||||
.into_iter()
|
||||
.flat_map(|r| Uuid::from_str(&r).ok())
|
||||
.collect();
|
||||
sync_chat_documents(user_service, external_service, rag_ids).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -667,7 +678,7 @@ impl AIManager {
|
|||
async fn sync_chat_documents(
|
||||
user_service: Arc<dyn AIUserService>,
|
||||
external_service: Arc<dyn AIExternalService>,
|
||||
rag_ids: Vec<String>,
|
||||
rag_ids: Vec<Uuid>,
|
||||
) -> FlowyResult<()> {
|
||||
if rag_ids.is_empty() {
|
||||
return Ok(());
|
||||
|
@ -697,7 +708,7 @@ async fn sync_chat_documents(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn save_chat(conn: DBConnection, chat_id: &str) -> FlowyResult<()> {
|
||||
fn save_chat(conn: DBConnection, chat_id: &Uuid) -> FlowyResult<()> {
|
||||
let row = ChatTable {
|
||||
chat_id: chat_id.to_string(),
|
||||
created_at: timestamp(),
|
||||
|
@ -716,7 +727,7 @@ async fn refresh_chat_setting(
|
|||
user_service: &Arc<dyn AIUserService>,
|
||||
cloud_service: &Arc<AICloudServiceMiddleware>,
|
||||
store_preferences: &Arc<KVStorePreferences>,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
) -> FlowyResult<ChatSettings> {
|
||||
info!("[Chat] refresh chat:{} setting", chat_id);
|
||||
let workspace_id = user_service.workspace_id()?;
|
||||
|
@ -728,15 +739,18 @@ async fn refresh_chat_setting(
|
|||
error!("failed to set chat settings: {}", err);
|
||||
}
|
||||
|
||||
chat_notification_builder(chat_id, ChatNotification::DidUpdateChatSettings)
|
||||
.payload(ChatSettingsPB {
|
||||
rag_ids: settings.rag_ids.clone(),
|
||||
})
|
||||
.send();
|
||||
chat_notification_builder(
|
||||
&chat_id.to_string(),
|
||||
ChatNotification::DidUpdateChatSettings,
|
||||
)
|
||||
.payload(ChatSettingsPB {
|
||||
rag_ids: settings.rag_ids.clone(),
|
||||
})
|
||||
.send();
|
||||
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
fn setting_store_key(chat_id: &str) -> String {
|
||||
format!("chat_settings_{}", chat_id)
|
||||
fn setting_store_key(chat_id: &Uuid) -> String {
|
||||
format!("chat_settings_{}", chat_id.to_string())
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ use std::sync::atomic::{AtomicBool, AtomicI64};
|
|||
use std::sync::Arc;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use tracing::{error, instrument, trace};
|
||||
use uuid::Uuid;
|
||||
|
||||
enum PrevMessageState {
|
||||
HasMore,
|
||||
|
@ -31,7 +32,7 @@ enum PrevMessageState {
|
|||
}
|
||||
|
||||
pub struct Chat {
|
||||
chat_id: String,
|
||||
chat_id: Uuid,
|
||||
uid: i64,
|
||||
user_service: Arc<dyn AIUserService>,
|
||||
chat_service: Arc<AICloudServiceMiddleware>,
|
||||
|
@ -44,7 +45,7 @@ pub struct Chat {
|
|||
impl Chat {
|
||||
pub fn new(
|
||||
uid: i64,
|
||||
chat_id: String,
|
||||
chat_id: Uuid,
|
||||
user_service: Arc<dyn AIUserService>,
|
||||
chat_service: Arc<AICloudServiceMiddleware>,
|
||||
) -> Chat {
|
||||
|
@ -197,7 +198,7 @@ impl Chat {
|
|||
answer_stream_port: i64,
|
||||
answer_stream_buffer: Arc<Mutex<StringBuffer>>,
|
||||
uid: i64,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
question_id: i64,
|
||||
format: ResponseFormat,
|
||||
ai_model: Option<AIModel>,
|
||||
|
@ -254,7 +255,7 @@ impl Chat {
|
|||
.send(StreamMessage::OnError(err.msg.clone()).to_string())
|
||||
.await;
|
||||
let pb = ChatMessageErrorPB {
|
||||
chat_id: chat_id.clone(),
|
||||
chat_id: chat_id.to_string(),
|
||||
error_message: err.to_string(),
|
||||
};
|
||||
chat_notification_builder(&chat_id, ChatNotification::StreamChatMessageError)
|
||||
|
@ -293,7 +294,7 @@ impl Chat {
|
|||
}
|
||||
|
||||
let pb = ChatMessageErrorPB {
|
||||
chat_id: chat_id.clone(),
|
||||
chat_id: chat_id.to_string(),
|
||||
error_message: err.to_string(),
|
||||
};
|
||||
chat_notification_builder(&chat_id, ChatNotification::StreamChatMessageError)
|
||||
|
@ -566,7 +567,7 @@ impl Chat {
|
|||
let conn = self.user_service.sqlite_connection(self.uid)?;
|
||||
let records = select_chat_messages(
|
||||
conn,
|
||||
&self.chat_id,
|
||||
&self.chat_id.to_string(),
|
||||
limit,
|
||||
after_message_id,
|
||||
before_message_id,
|
||||
|
@ -628,7 +629,7 @@ impl Chat {
|
|||
|
||||
fn save_chat_message_disk(
|
||||
conn: DBConnection,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
messages: Vec<ChatMessage>,
|
||||
) -> FlowyResult<()> {
|
||||
let records = messages
|
||||
|
@ -683,7 +684,7 @@ impl StringBuffer {
|
|||
|
||||
pub(crate) fn save_and_notify_message(
|
||||
uid: i64,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
user_service: &Arc<dyn AIUserService>,
|
||||
message: ChatMessage,
|
||||
) -> Result<(), FlowyError> {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ai_manager::AIUserService;
|
||||
use crate::entities::{CompleteTextPB, CompleteTextTaskPB, CompletionTypePB};
|
||||
use allo_isolate::Isolate;
|
||||
use std::str::FromStr;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use flowy_ai_pub::cloud::{
|
||||
|
@ -15,7 +16,8 @@ use lib_infra::isolate_stream::IsolateSink;
|
|||
use crate::stream_message::StreamMessage;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::select;
|
||||
use tracing::info;
|
||||
use tracing::{error, info};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct AICompletion {
|
||||
tasks: Arc<DashMap<String, tokio::sync::mpsc::Sender<()>>>,
|
||||
|
@ -77,7 +79,7 @@ impl AICompletion {
|
|||
}
|
||||
|
||||
pub struct CompletionTask {
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
task_id: String,
|
||||
stop_rx: tokio::sync::mpsc::Receiver<()>,
|
||||
context: CompleteTextPB,
|
||||
|
@ -87,7 +89,7 @@ pub struct CompletionTask {
|
|||
|
||||
impl CompletionTask {
|
||||
pub fn new(
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
context: CompleteTextPB,
|
||||
preferred_model: Option<AIModel>,
|
||||
cloud_service: Weak<dyn ChatCloudService>,
|
||||
|
@ -122,59 +124,63 @@ impl CompletionTask {
|
|||
let _ = sink.send("start:".to_string()).await;
|
||||
let completion_history = Some(self.context.history.iter().map(Into::into).collect());
|
||||
let format = self.context.format.map(Into::into).unwrap_or_default();
|
||||
let params = CompleteTextParams {
|
||||
text: self.context.text,
|
||||
completion_type: Some(complete_type),
|
||||
metadata: Some(CompletionMetadata {
|
||||
object_id: self.context.object_id,
|
||||
workspace_id: Some(self.workspace_id.clone()),
|
||||
rag_ids: Some(self.context.rag_ids),
|
||||
completion_history,
|
||||
custom_prompt: self
|
||||
.context
|
||||
.custom_prompt
|
||||
.map(|v| CustomPrompt { system: v }),
|
||||
}),
|
||||
format,
|
||||
};
|
||||
if let Ok(object_id) = Uuid::from_str(&self.context.object_id) {
|
||||
let params = CompleteTextParams {
|
||||
text: self.context.text,
|
||||
completion_type: Some(complete_type),
|
||||
metadata: Some(CompletionMetadata {
|
||||
object_id,
|
||||
workspace_id: Some(self.workspace_id.clone()),
|
||||
rag_ids: Some(self.context.rag_ids),
|
||||
completion_history,
|
||||
custom_prompt: self
|
||||
.context
|
||||
.custom_prompt
|
||||
.map(|v| CustomPrompt { system: v }),
|
||||
}),
|
||||
format,
|
||||
};
|
||||
|
||||
info!("start completion: {:?}", params);
|
||||
match cloud_service
|
||||
.stream_complete(&self.workspace_id, params, self.preferred_model)
|
||||
.await
|
||||
{
|
||||
Ok(mut stream) => loop {
|
||||
select! {
|
||||
_ = self.stop_rx.recv() => {
|
||||
return;
|
||||
},
|
||||
result = stream.next() => {
|
||||
match result {
|
||||
Some(Ok(data)) => {
|
||||
match data {
|
||||
CompletionStreamValue::Answer{ value } => {
|
||||
let _ = sink.send(format!("data:{}", value)).await;
|
||||
info!("start completion: {:?}", params);
|
||||
match cloud_service
|
||||
.stream_complete(&self.workspace_id, params, self.preferred_model)
|
||||
.await
|
||||
{
|
||||
Ok(mut stream) => loop {
|
||||
select! {
|
||||
_ = self.stop_rx.recv() => {
|
||||
return;
|
||||
},
|
||||
result = stream.next() => {
|
||||
match result {
|
||||
Some(Ok(data)) => {
|
||||
match data {
|
||||
CompletionStreamValue::Answer{ value } => {
|
||||
let _ = sink.send(format!("data:{}", value)).await;
|
||||
}
|
||||
CompletionStreamValue::Comment{ value } => {
|
||||
let _ = sink.send(format!("comment:{}", value)).await;
|
||||
}
|
||||
}
|
||||
CompletionStreamValue::Comment{ value } => {
|
||||
let _ = sink.send(format!("comment:{}", value)).await;
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(Err(error)) => {
|
||||
handle_error(&mut sink, error).await;
|
||||
return;
|
||||
},
|
||||
None => {
|
||||
let _ = sink.send(format!("finish:{}", self.task_id)).await;
|
||||
return;
|
||||
},
|
||||
},
|
||||
Some(Err(error)) => {
|
||||
handle_error(&mut sink, error).await;
|
||||
return;
|
||||
},
|
||||
None => {
|
||||
let _ = sink.send(format!("finish:{}", self.task_id)).await;
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(error) => {
|
||||
handle_error(&mut sink, error).await;
|
||||
},
|
||||
}
|
||||
},
|
||||
Err(error) => {
|
||||
handle_error(&mut sink, error).await;
|
||||
},
|
||||
}
|
||||
} else {
|
||||
error!("Invalid uuid: {}", self.context.object_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use af_plugin::core::plugin::RunningState;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::local_ai::controller::LocalAISetting;
|
||||
use crate::local_ai::resource::PendingResource;
|
||||
use af_plugin::core::plugin::RunningState;
|
||||
use flowy_ai_pub::cloud::{
|
||||
AIModel, ChatMessage, ChatMessageMetadata, ChatMessageType, CompletionMessage, LLMModel,
|
||||
OutputContent, OutputLayout, RelatedQuestion, RepeatedChatMessage, RepeatedRelatedQuestion,
|
||||
|
@ -10,6 +8,8 @@ use flowy_ai_pub::cloud::{
|
|||
};
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use lib_infra::validator_fn::required_not_empty_str;
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Default, ProtoBuf, Validate, Clone, Debug)]
|
||||
|
@ -78,7 +78,7 @@ pub struct StreamChatPayloadPB {
|
|||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct StreamMessageParams {
|
||||
pub chat_id: String,
|
||||
pub chat_id: Uuid,
|
||||
pub message: String,
|
||||
pub message_type: ChatMessageType,
|
||||
pub answer_stream_port: i64,
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::ai_manager::{AIManager, GLOBAL_ACTIVE_MODEL_KEY};
|
||||
use crate::completion::AICompletion;
|
||||
use crate::entities::*;
|
||||
|
@ -10,8 +7,12 @@ use flowy_ai_pub::cloud::{
|
|||
};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::trace;
|
||||
use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
|
||||
fn upgrade_ai_manager(ai_manager: AFPluginState<Weak<AIManager>>) -> FlowyResult<Arc<AIManager>> {
|
||||
|
@ -70,6 +71,7 @@ pub(crate) async fn stream_chat_message_handler(
|
|||
|
||||
trace!("Stream chat message with metadata: {:?}", metadata);
|
||||
|
||||
let chat_id = Uuid::from_str(&chat_id)?;
|
||||
let params = StreamMessageParams {
|
||||
chat_id,
|
||||
message,
|
||||
|
@ -91,11 +93,12 @@ pub(crate) async fn regenerate_response_handler(
|
|||
ai_manager: AFPluginState<Weak<AIManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let data = data.try_into_inner()?;
|
||||
let chat_id = Uuid::from_str(&data.chat_id)?;
|
||||
|
||||
let ai_manager = upgrade_ai_manager(ai_manager)?;
|
||||
ai_manager
|
||||
.stream_regenerate_response(
|
||||
&data.chat_id,
|
||||
&chat_id,
|
||||
data.answer_message_id,
|
||||
data.answer_stream_port,
|
||||
data.format,
|
||||
|
@ -147,8 +150,9 @@ pub(crate) async fn load_prev_message_handler(
|
|||
let data = data.into_inner();
|
||||
data.validate()?;
|
||||
|
||||
let chat_id = Uuid::from_str(&data.chat_id)?;
|
||||
let messages = ai_manager
|
||||
.load_prev_chat_messages(&data.chat_id, data.limit, data.before_message_id)
|
||||
.load_prev_chat_messages(&chat_id, data.limit, data.before_message_id)
|
||||
.await?;
|
||||
data_result_ok(messages)
|
||||
}
|
||||
|
@ -162,8 +166,9 @@ pub(crate) async fn load_next_message_handler(
|
|||
let data = data.into_inner();
|
||||
data.validate()?;
|
||||
|
||||
let chat_id = Uuid::from_str(&data.chat_id)?;
|
||||
let messages = ai_manager
|
||||
.load_latest_chat_messages(&data.chat_id, data.limit, data.after_message_id)
|
||||
.load_latest_chat_messages(&chat_id, data.limit, data.after_message_id)
|
||||
.await?;
|
||||
data_result_ok(messages)
|
||||
}
|
||||
|
@ -175,8 +180,9 @@ pub(crate) async fn get_related_question_handler(
|
|||
) -> DataResult<RepeatedRelatedQuestionPB, FlowyError> {
|
||||
let ai_manager = upgrade_ai_manager(ai_manager)?;
|
||||
let data = data.into_inner();
|
||||
let chat_id = Uuid::from_str(&data.chat_id)?;
|
||||
let messages = ai_manager
|
||||
.get_related_questions(&data.chat_id, data.message_id)
|
||||
.get_related_questions(&chat_id, data.message_id)
|
||||
.await?;
|
||||
data_result_ok(messages)
|
||||
}
|
||||
|
@ -188,8 +194,9 @@ pub(crate) async fn get_answer_handler(
|
|||
) -> DataResult<ChatMessagePB, FlowyError> {
|
||||
let ai_manager = upgrade_ai_manager(ai_manager)?;
|
||||
let data = data.into_inner();
|
||||
let chat_id = Uuid::from_str(&data.chat_id)?;
|
||||
let message = ai_manager
|
||||
.generate_answer(&data.chat_id, data.message_id)
|
||||
.generate_answer(&chat_id, data.message_id)
|
||||
.await?;
|
||||
data_result_ok(message)
|
||||
}
|
||||
|
@ -203,7 +210,8 @@ pub(crate) async fn stop_stream_handler(
|
|||
data.validate()?;
|
||||
|
||||
let ai_manager = upgrade_ai_manager(ai_manager)?;
|
||||
ai_manager.stop_stream(&data.chat_id).await?;
|
||||
let chat_id = Uuid::from_str(&data.chat_id)?;
|
||||
ai_manager.stop_stream(&chat_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -273,7 +281,8 @@ pub(crate) async fn chat_file_handler(
|
|||
|
||||
tracing::debug!("File size: {} bytes", file_size);
|
||||
let ai_manager = upgrade_ai_manager(ai_manager)?;
|
||||
ai_manager.chat_with_file(&data.chat_id, file_path).await?;
|
||||
let chat_id = Uuid::from_str(&data.chat_id)?;
|
||||
ai_manager.chat_with_file(&chat_id, file_path).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -332,6 +341,7 @@ pub(crate) async fn get_chat_settings_handler(
|
|||
ai_manager: AFPluginState<Weak<AIManager>>,
|
||||
) -> DataResult<ChatSettingsPB, FlowyError> {
|
||||
let chat_id = data.try_into_inner()?.value;
|
||||
let chat_id = Uuid::from_str(&chat_id)?;
|
||||
let ai_manager = upgrade_ai_manager(ai_manager)?;
|
||||
let rag_ids = ai_manager.get_rag_ids(&chat_id).await?;
|
||||
let pb = ChatSettingsPB { rag_ids };
|
||||
|
@ -345,9 +355,8 @@ pub(crate) async fn update_chat_settings_handler(
|
|||
) -> FlowyResult<()> {
|
||||
let params = data.try_into_inner()?;
|
||||
let ai_manager = upgrade_ai_manager(ai_manager)?;
|
||||
ai_manager
|
||||
.update_rag_ids(¶ms.chat_id.value, params.rag_ids)
|
||||
.await?;
|
||||
let chat_id = Uuid::from_str(¶ms.chat_id.value)?;
|
||||
ai_manager.update_rag_ids(&chat_id, params.rag_ids).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ use std::sync::Arc;
|
|||
use tokio::select;
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::{debug, error, info, instrument};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct LocalAISetting {
|
||||
|
@ -51,7 +52,7 @@ const LOCAL_AI_SETTING_KEY: &str = "appflowy_local_ai_setting:v1";
|
|||
pub struct LocalAIController {
|
||||
ai_plugin: Arc<OllamaAIPlugin>,
|
||||
resource: Arc<LocalAIResourceController>,
|
||||
current_chat_id: ArcSwapOption<String>,
|
||||
current_chat_id: ArcSwapOption<Uuid>,
|
||||
store_preferences: Arc<KVStorePreferences>,
|
||||
user_service: Arc<dyn AIUserService>,
|
||||
#[allow(dead_code)]
|
||||
|
@ -240,7 +241,7 @@ impl LocalAIController {
|
|||
Some(self.resource.get_llm_setting().chat_model_name)
|
||||
}
|
||||
|
||||
pub fn open_chat(&self, chat_id: &str) {
|
||||
pub fn open_chat(&self, chat_id: &Uuid) {
|
||||
if !self.is_enabled() {
|
||||
return;
|
||||
}
|
||||
|
@ -252,9 +253,7 @@ impl LocalAIController {
|
|||
self.close_chat(current_chat_id);
|
||||
}
|
||||
|
||||
self
|
||||
.current_chat_id
|
||||
.store(Some(Arc::new(chat_id.to_string())));
|
||||
self.current_chat_id.store(Some(Arc::new(chat_id.clone())));
|
||||
let chat_id = chat_id.to_string();
|
||||
let weak_ctrl = Arc::downgrade(&self.ai_plugin);
|
||||
tokio::spawn(async move {
|
||||
|
@ -266,7 +265,7 @@ impl LocalAIController {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn close_chat(&self, chat_id: &str) {
|
||||
pub fn close_chat(&self, chat_id: &Uuid) {
|
||||
if !self.is_running() {
|
||||
return;
|
||||
}
|
||||
|
@ -383,7 +382,7 @@ impl LocalAIController {
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn index_message_metadata(
|
||||
&self,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
metadata_list: &[ChatMessageMetadata],
|
||||
index_process_sink: &mut (impl Sink<String> + Unpin),
|
||||
) -> FlowyResult<()> {
|
||||
|
@ -434,7 +433,7 @@ impl LocalAIController {
|
|||
|
||||
async fn process_index_file(
|
||||
&self,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
file_path: PathBuf,
|
||||
index_metadata: &HashMap<String, serde_json::Value>,
|
||||
index_process_sink: &mut (impl Sink<String> + Unpin),
|
||||
|
@ -456,7 +455,11 @@ impl LocalAIController {
|
|||
|
||||
let result = self
|
||||
.ai_plugin
|
||||
.embed_file(chat_id, file_path, Some(index_metadata.clone()))
|
||||
.embed_file(
|
||||
&chat_id.to_string(),
|
||||
file_path,
|
||||
Some(index_metadata.clone()),
|
||||
)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_) => {
|
||||
|
@ -616,6 +619,6 @@ impl LLMResourceService for LLMResourceServiceImpl {
|
|||
}
|
||||
|
||||
const APPFLOWY_LOCAL_AI_ENABLED: &str = "appflowy_local_ai_enabled";
|
||||
fn local_ai_enabled_key(workspace_id: &str) -> String {
|
||||
format!("{}:{}", APPFLOWY_LOCAL_AI_ENABLED, workspace_id)
|
||||
fn local_ai_enabled_key(workspace_id: &Uuid) -> String {
|
||||
format!("{}:{}", APPFLOWY_LOCAL_AI_ENABLED, workspace_id.to_string())
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ use serde_json::{json, Value};
|
|||
use std::path::Path;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{info, trace};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct AICloudServiceMiddleware {
|
||||
cloud_service: Arc<dyn ChatCloudService>,
|
||||
|
@ -55,7 +56,7 @@ impl AICloudServiceMiddleware {
|
|||
|
||||
pub async fn index_message_metadata(
|
||||
&self,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
metadata_list: &[ChatMessageMetadata],
|
||||
index_process_sink: &mut (impl Sink<String> + Unpin),
|
||||
) -> Result<(), FlowyError> {
|
||||
|
@ -114,9 +115,9 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
async fn create_chat(
|
||||
&self,
|
||||
uid: &i64,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
rag_ids: Vec<String>,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
.cloud_service
|
||||
|
@ -126,8 +127,8 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn create_question(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
message_type: ChatMessageType,
|
||||
metadata: &[ChatMessageMetadata],
|
||||
|
@ -140,8 +141,8 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn create_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
question_id: i64,
|
||||
metadata: Option<serde_json::Value>,
|
||||
|
@ -154,8 +155,8 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn stream_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
format: ResponseFormat,
|
||||
ai_model: Option<AIModel>,
|
||||
|
@ -171,7 +172,12 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
let row = self.get_message_record(message_id)?;
|
||||
match self
|
||||
.local_ai
|
||||
.stream_question(chat_id, &row.content, Some(json!(format)), json!({}))
|
||||
.stream_question(
|
||||
&chat_id.to_string(),
|
||||
&row.content,
|
||||
Some(json!(format)),
|
||||
json!({}),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(stream) => Ok(QuestionStream::new(stream).boxed()),
|
||||
|
@ -195,13 +201,17 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn get_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
question_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
if self.local_ai.is_running() {
|
||||
let content = self.get_message_record(question_message_id)?.content;
|
||||
match self.local_ai.ask_question(chat_id, &content).await {
|
||||
match self
|
||||
.local_ai
|
||||
.ask_question(&chat_id.to_string(), &content)
|
||||
.await
|
||||
{
|
||||
Ok(answer) => {
|
||||
let message = self
|
||||
.cloud_service
|
||||
|
@ -224,8 +234,8 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn get_chat_messages(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
offset: MessageCursor,
|
||||
limit: u64,
|
||||
) -> Result<RepeatedChatMessage, FlowyError> {
|
||||
|
@ -237,26 +247,26 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn get_question_from_answer_id(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
answer_id: i64,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
answer_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
self
|
||||
.cloud_service
|
||||
.get_question_from_answer_id(workspace_id, chat_id, answer_id)
|
||||
.get_question_from_answer_id(workspace_id, chat_id, answer_message_id)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_related_message(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
) -> Result<RepeatedRelatedQuestion, FlowyError> {
|
||||
if self.local_ai.is_running() {
|
||||
let questions = self
|
||||
.local_ai
|
||||
.get_related_question(chat_id)
|
||||
.get_related_question(&chat_id.to_string())
|
||||
.await
|
||||
.map_err(|err| FlowyError::local_ai().with_context(err))?;
|
||||
trace!("LocalAI related questions: {:?}", questions);
|
||||
|
@ -280,7 +290,7 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn stream_complete(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
params: CompleteTextParams,
|
||||
ai_model: Option<AIModel>,
|
||||
) -> Result<StreamComplete, FlowyError> {
|
||||
|
@ -329,15 +339,15 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn embed_file(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
file_path: &Path,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
metadata: Option<HashMap<String, Value>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
if self.local_ai.is_running() {
|
||||
self
|
||||
.local_ai
|
||||
.embed_file(chat_id, file_path.to_path_buf(), metadata)
|
||||
.embed_file(&chat_id.to_string(), file_path.to_path_buf(), metadata)
|
||||
.await
|
||||
.map_err(|err| FlowyError::local_ai().with_context(err))?;
|
||||
Ok(())
|
||||
|
@ -349,21 +359,21 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_local_ai_config(&self, workspace_id: &str) -> Result<LocalAIConfig, FlowyError> {
|
||||
async fn get_local_ai_config(&self, workspace_id: &Uuid) -> Result<LocalAIConfig, FlowyError> {
|
||||
self.cloud_service.get_local_ai_config(workspace_id).await
|
||||
}
|
||||
|
||||
async fn get_workspace_plan(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<SubscriptionPlan>, FlowyError> {
|
||||
self.cloud_service.get_workspace_plan(workspace_id).await
|
||||
}
|
||||
|
||||
async fn get_chat_settings(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<ChatSettings, FlowyError> {
|
||||
self
|
||||
.cloud_service
|
||||
|
@ -373,8 +383,8 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
|
||||
async fn update_chat_settings(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
params: UpdateChatParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
|
@ -383,11 +393,11 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn get_available_models(&self, workspace_id: &str) -> Result<ModelList, FlowyError> {
|
||||
async fn get_available_models(&self, workspace_id: &Uuid) -> Result<ModelList, FlowyError> {
|
||||
self.cloud_service.get_available_models(workspace_id).await
|
||||
}
|
||||
|
||||
async fn get_workspace_default_model(&self, workspace_id: &str) -> Result<String, FlowyError> {
|
||||
async fn get_workspace_default_model(&self, workspace_id: &Uuid) -> Result<String, FlowyError> {
|
||||
self
|
||||
.cloud_service
|
||||
.get_workspace_default_model(workspace_id)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use flowy_derive::ProtoBuf_Enum;
|
||||
use flowy_notification::NotificationBuilder;
|
||||
use tracing::trace;
|
||||
|
||||
const CHAT_OBSERVABLE_SOURCE: &str = "Chat";
|
||||
pub const APPFLOWY_AI_NOTIFICATION_KEY: &str = "appflowy_ai_plugin";
|
||||
|
@ -39,7 +40,12 @@ impl std::convert::From<i32> for ChatNotification {
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace")]
|
||||
pub(crate) fn chat_notification_builder(id: &str, ty: ChatNotification) -> NotificationBuilder {
|
||||
NotificationBuilder::new(id, ty, CHAT_OBSERVABLE_SOURCE)
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
pub(crate) fn chat_notification_builder<T: ToString>(
|
||||
id: T,
|
||||
ty: ChatNotification,
|
||||
) -> NotificationBuilder {
|
||||
let id = id.to_string();
|
||||
trace!("chat_notification_builder: id = {id}, ty = {ty:?}");
|
||||
NotificationBuilder::new(&id, ty, CHAT_OBSERVABLE_SOURCE)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ collab = { workspace = true }
|
|||
#collab = { workspace = true, features = ["verbose_log"] }
|
||||
|
||||
diesel.workspace = true
|
||||
uuid.workspace = true
|
||||
flowy-storage = { workspace = true }
|
||||
flowy-storage-pub = { workspace = true }
|
||||
client-api.workspace = true
|
||||
|
@ -56,8 +55,7 @@ lib-infra = { workspace = true }
|
|||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_repr.workspace = true
|
||||
futures.workspace = true
|
||||
walkdir = "2.4.0"
|
||||
uuid.workspace = true
|
||||
sysinfo = "0.30.5"
|
||||
semver = { version = "1.0.22", features = ["serde"] }
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ use std::collections::HashMap;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{error, info};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct ChatDepsResolver;
|
||||
|
||||
|
@ -56,9 +57,9 @@ struct ChatQueryServiceImpl {
|
|||
impl AIExternalService for ChatQueryServiceImpl {
|
||||
async fn query_chat_rag_ids(
|
||||
&self,
|
||||
parent_view_id: &str,
|
||||
chat_id: &str,
|
||||
) -> Result<Vec<String>, FlowyError> {
|
||||
parent_view_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<Vec<Uuid>, FlowyError> {
|
||||
let mut ids = self
|
||||
.folder_service
|
||||
.get_surrounding_view_ids_with_view_layout(parent_view_id, ViewLayout::Document)
|
||||
|
@ -72,9 +73,9 @@ impl AIExternalService for ChatQueryServiceImpl {
|
|||
}
|
||||
async fn sync_rag_documents(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
rag_ids: Vec<String>,
|
||||
mut rag_metadata_map: HashMap<String, AFCollabMetadata>,
|
||||
workspace_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
mut rag_metadata_map: HashMap<Uuid, AFCollabMetadata>,
|
||||
) -> Result<Vec<AFCollabMetadata>, FlowyError> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
|
@ -96,7 +97,7 @@ impl AIExternalService for ChatQueryServiceImpl {
|
|||
if let Ok(prev_sv) = StateVector::decode_v1(&metadata.prev_sync_state_vector) {
|
||||
let collab = Collab::new_with_source(
|
||||
CollabOrigin::Empty,
|
||||
&rag_id,
|
||||
&rag_id.to_string(),
|
||||
DataSource::DocStateV1(query_collab.encoded_collab.doc_state.to_vec()),
|
||||
vec![],
|
||||
false,
|
||||
|
@ -125,7 +126,7 @@ impl AIExternalService for ChatQueryServiceImpl {
|
|||
} else {
|
||||
info!("[Chat] full sync rag document: {}", rag_id);
|
||||
result.push(AFCollabMetadata {
|
||||
object_id: rag_id,
|
||||
object_id: rag_id.to_string(),
|
||||
updated_at: timestamp(),
|
||||
prev_sync_state_vector: query_collab.encoded_collab.state_vector.to_vec(),
|
||||
collab_type: CollabType::Document as i32,
|
||||
|
@ -136,7 +137,7 @@ impl AIExternalService for ChatQueryServiceImpl {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
async fn notify_did_send_message(&self, chat_id: &str, message: &str) -> Result<(), FlowyError> {
|
||||
async fn notify_did_send_message(&self, chat_id: &Uuid, message: &str) -> Result<(), FlowyError> {
|
||||
info!(
|
||||
"notify_did_send_message: chat_id: {}, message: {}",
|
||||
chat_id, message
|
||||
|
@ -169,7 +170,7 @@ impl AIUserService for ChatUserServiceImpl {
|
|||
self.upgrade_user()?.device_id()
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
|
||||
|
|
|
@ -7,16 +7,6 @@ use collab::core::origin::{CollabClient, CollabOrigin};
|
|||
use collab::entity::EncodedCollab;
|
||||
use collab::preclude::CollabPlugin;
|
||||
use collab_entity::CollabType;
|
||||
use flowy_search_pub::cloud::SearchCloudService;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use collab_integrate::collab_builder::{
|
||||
CollabCloudPluginProvider, CollabPluginProviderContext, CollabPluginProviderType,
|
||||
};
|
||||
|
@ -37,12 +27,24 @@ use flowy_folder_pub::cloud::{
|
|||
Workspace, WorkspaceRecord,
|
||||
};
|
||||
use flowy_folder_pub::entities::PublishPayload;
|
||||
use flowy_search_pub::cloud::SearchCloudService;
|
||||
use flowy_server_pub::af_cloud_config::AFCloudConfiguration;
|
||||
use flowy_storage_pub::cloud::{ObjectIdentity, ObjectValue, StorageCloudService};
|
||||
use flowy_storage_pub::storage::{CompletedPartRequest, CreateUploadResponse, UploadPartResponse};
|
||||
use flowy_user_pub::cloud::{UserCloudService, UserCloudServiceProvider};
|
||||
use flowy_user_pub::entities::{Authenticator, UserTokenState};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tracing::log::error;
|
||||
use tracing::{debug, info};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::server_layer::{Server, ServerProvider};
|
||||
|
||||
|
@ -82,7 +84,7 @@ impl StorageCloudService for ServerProvider {
|
|||
|
||||
async fn get_object_url_v1(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
file_id: &str,
|
||||
) -> FlowyResult<String> {
|
||||
|
@ -93,7 +95,7 @@ impl StorageCloudService for ServerProvider {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn parse_object_url_v1(&self, url: &str) -> Option<(String, String, String)> {
|
||||
async fn parse_object_url_v1(&self, url: &str) -> Option<(Uuid, String, String)> {
|
||||
self
|
||||
.get_server()
|
||||
.ok()?
|
||||
|
@ -104,7 +106,7 @@ impl StorageCloudService for ServerProvider {
|
|||
|
||||
async fn create_upload(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
file_id: &str,
|
||||
content_type: &str,
|
||||
|
@ -119,7 +121,7 @@ impl StorageCloudService for ServerProvider {
|
|||
|
||||
async fn upload_part(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
upload_id: &str,
|
||||
file_id: &str,
|
||||
|
@ -142,7 +144,7 @@ impl StorageCloudService for ServerProvider {
|
|||
|
||||
async fn complete_upload(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
upload_id: &str,
|
||||
file_id: &str,
|
||||
|
@ -233,10 +235,9 @@ impl FolderCloudService for ServerProvider {
|
|||
server.folder_service().create_workspace(uid, &name).await
|
||||
}
|
||||
|
||||
async fn open_workspace(&self, workspace_id: &str) -> Result<(), FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
async fn open_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server.folder_service().open_workspace(&workspace_id).await
|
||||
server.folder_service().open_workspace(workspace_id).await
|
||||
}
|
||||
|
||||
async fn get_all_workspace(&self) -> Result<Vec<WorkspaceRecord>, FlowyError> {
|
||||
|
@ -246,7 +247,7 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn get_folder_data(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: &i64,
|
||||
) -> Result<Option<FolderData>, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
@ -272,10 +273,10 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn get_folder_doc_state(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
collab_type: CollabType,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
||||
|
@ -287,7 +288,7 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn batch_create_folder_collab_objects(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
objects: Vec<FolderCollabParams>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
@ -307,7 +308,7 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn publish_view(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
payload: Vec<PublishPayload>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
@ -320,8 +321,8 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn unpublish_views(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
view_ids: Vec<String>,
|
||||
workspace_id: &Uuid,
|
||||
view_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
|
@ -330,15 +331,15 @@ impl FolderCloudService for ServerProvider {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn get_publish_info(&self, view_id: &str) -> Result<PublishInfo, FlowyError> {
|
||||
async fn get_publish_info(&self, view_id: &Uuid) -> Result<PublishInfo, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server.folder_service().get_publish_info(view_id).await
|
||||
}
|
||||
|
||||
async fn set_publish_name(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
view_id: String,
|
||||
workspace_id: &Uuid,
|
||||
view_id: Uuid,
|
||||
new_name: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
@ -350,7 +351,7 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn set_publish_namespace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
new_namespace: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
@ -360,7 +361,7 @@ impl FolderCloudService for ServerProvider {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn get_publish_namespace(&self, workspace_id: &str) -> Result<String, FlowyError> {
|
||||
async fn get_publish_namespace(&self, workspace_id: &Uuid) -> Result<String, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
.folder_service()
|
||||
|
@ -371,7 +372,7 @@ impl FolderCloudService for ServerProvider {
|
|||
/// List all published views of the current workspace.
|
||||
async fn list_published_views(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<PublishInfoView>, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
|
@ -382,7 +383,7 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn get_default_published_view_info(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<PublishInfo, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
|
@ -393,7 +394,7 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn set_default_published_view(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
view_id: uuid::Uuid,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
@ -403,7 +404,7 @@ impl FolderCloudService for ServerProvider {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn remove_default_published_view(&self, workspace_id: &str) -> Result<(), FlowyError> {
|
||||
async fn remove_default_published_view(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
.folder_service()
|
||||
|
@ -421,7 +422,7 @@ impl FolderCloudService for ServerProvider {
|
|||
|
||||
async fn full_sync_collab_object(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
params: FullSyncCollabParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
|
@ -436,24 +437,22 @@ impl FolderCloudService for ServerProvider {
|
|||
impl DatabaseCloudService for ServerProvider {
|
||||
async fn get_database_encode_collab(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let server = self.get_server()?;
|
||||
let database_id = object_id.to_string();
|
||||
server
|
||||
.database_service()
|
||||
.get_database_encode_collab(&database_id, collab_type, &workspace_id)
|
||||
.get_database_encode_collab(object_id, collab_type, &workspace_id)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn create_database_encode_collab(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
@ -465,30 +464,28 @@ impl DatabaseCloudService for ServerProvider {
|
|||
|
||||
async fn batch_get_database_encode_collab(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
object_ids: Vec<Uuid>,
|
||||
object_ty: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<EncodeCollabByOid, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let server = self.get_server()?;
|
||||
|
||||
server
|
||||
.database_service()
|
||||
.batch_get_database_encode_collab(object_ids, object_ty, &workspace_id)
|
||||
.batch_get_database_encode_collab(object_ids, object_ty, workspace_id)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_database_collab_object_snapshots(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
limit: usize,
|
||||
) -> Result<Vec<DatabaseSnapshot>, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
let database_id = object_id.to_string();
|
||||
|
||||
server
|
||||
.database_service()
|
||||
.get_database_collab_object_snapshots(&database_id, limit)
|
||||
.get_database_collab_object_snapshots(&object_id, limit)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
@ -497,29 +494,29 @@ impl DatabaseCloudService for ServerProvider {
|
|||
impl DatabaseAIService for ServerProvider {
|
||||
async fn summary_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
_workspace_id: &Uuid,
|
||||
_object_id: &Uuid,
|
||||
_summary_row: SummaryRowContent,
|
||||
) -> Result<String, FlowyError> {
|
||||
self
|
||||
.get_server()?
|
||||
.database_ai_service()
|
||||
.ok_or_else(FlowyError::not_support)?
|
||||
.summary_database_row(workspace_id, object_id, summary_row)
|
||||
.summary_database_row(_workspace_id, _object_id, _summary_row)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn translate_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
translate_row: TranslateRowContent,
|
||||
language: &str,
|
||||
_workspace_id: &Uuid,
|
||||
_translate_row: TranslateRowContent,
|
||||
_language: &str,
|
||||
) -> Result<TranslateRowResponse, FlowyError> {
|
||||
self
|
||||
.get_server()?
|
||||
.database_ai_service()
|
||||
.ok_or_else(FlowyError::not_support)?
|
||||
.translate_database_row(workspace_id, translate_row, language)
|
||||
.translate_database_row(_workspace_id, _translate_row, _language)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
@ -528,8 +525,8 @@ impl DatabaseAIService for ServerProvider {
|
|||
impl DocumentCloudService for ServerProvider {
|
||||
async fn get_document_doc_state(
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
|
@ -540,7 +537,7 @@ impl DocumentCloudService for ServerProvider {
|
|||
|
||||
async fn get_document_snapshots(
|
||||
&self,
|
||||
document_id: &str,
|
||||
document_id: &Uuid,
|
||||
limit: usize,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<DocumentSnapshot>, FlowyError> {
|
||||
|
@ -554,8 +551,8 @@ impl DocumentCloudService for ServerProvider {
|
|||
|
||||
async fn get_document_data(
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<DocumentData>, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
|
@ -566,8 +563,8 @@ impl DocumentCloudService for ServerProvider {
|
|||
|
||||
async fn create_document_collab(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
document_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
document_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
@ -611,26 +608,37 @@ impl CollabCloudPluginProvider for ServerProvider {
|
|||
collab_object.uid,
|
||||
collab_object.device_id.clone(),
|
||||
));
|
||||
let sync_object = SyncObject::new(
|
||||
&collab_object.object_id,
|
||||
&collab_object.workspace_id,
|
||||
collab_object.collab_type,
|
||||
&collab_object.device_id,
|
||||
);
|
||||
let (sink, stream) = (channel.sink(), channel.stream());
|
||||
let sink_config = SinkConfig::new().send_timeout(8);
|
||||
let sync_plugin = SyncPlugin::new(
|
||||
origin,
|
||||
sync_object,
|
||||
local_collab,
|
||||
sink,
|
||||
sink_config,
|
||||
stream,
|
||||
Some(channel),
|
||||
ws_connect_state,
|
||||
Some(Duration::from_secs(60)),
|
||||
);
|
||||
plugins.push(Box::new(sync_plugin));
|
||||
|
||||
if let (Ok(object_id), Ok(workspace_id)) = (
|
||||
Uuid::from_str(&collab_object.object_id),
|
||||
Uuid::from_str(&collab_object.workspace_id),
|
||||
) {
|
||||
let sync_object = SyncObject::new(
|
||||
object_id,
|
||||
workspace_id,
|
||||
collab_object.collab_type,
|
||||
&collab_object.device_id,
|
||||
);
|
||||
let (sink, stream) = (channel.sink(), channel.stream());
|
||||
let sink_config = SinkConfig::new().send_timeout(8);
|
||||
let sync_plugin = SyncPlugin::new(
|
||||
origin,
|
||||
sync_object,
|
||||
local_collab,
|
||||
sink,
|
||||
sink_config,
|
||||
stream,
|
||||
Some(channel),
|
||||
ws_connect_state,
|
||||
Some(Duration::from_secs(60)),
|
||||
);
|
||||
plugins.push(Box::new(sync_plugin));
|
||||
} else {
|
||||
error!(
|
||||
"Failed to parse collab object id: {}",
|
||||
collab_object.object_id
|
||||
);
|
||||
}
|
||||
},
|
||||
Ok(None) => {
|
||||
tracing::error!("🔴Failed to get collab ws channel: channel is none");
|
||||
|
@ -655,9 +663,9 @@ impl ChatCloudService for ServerProvider {
|
|||
async fn create_chat(
|
||||
&self,
|
||||
uid: &i64,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
rag_ids: Vec<String>,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server();
|
||||
server?
|
||||
|
@ -668,14 +676,12 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn create_question(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
message_type: ChatMessageType,
|
||||
metadata: &[ChatMessageMetadata],
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let chat_id = chat_id.to_string();
|
||||
let message = message.to_string();
|
||||
self
|
||||
.get_server()?
|
||||
|
@ -686,8 +692,8 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn create_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
question_id: i64,
|
||||
metadata: Option<serde_json::Value>,
|
||||
|
@ -701,14 +707,12 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn stream_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
format: ResponseFormat,
|
||||
ai_model: Option<AIModel>,
|
||||
) -> Result<StreamAnswer, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let chat_id = chat_id.to_string();
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
.chat_service()
|
||||
|
@ -718,8 +722,8 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn get_chat_messages(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
offset: MessageCursor,
|
||||
limit: u64,
|
||||
) -> Result<RepeatedChatMessage, FlowyError> {
|
||||
|
@ -732,8 +736,8 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn get_question_from_answer_id(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
answer_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
self
|
||||
|
@ -745,8 +749,8 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn get_related_message(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
) -> Result<RepeatedRelatedQuestion, FlowyError> {
|
||||
self
|
||||
|
@ -758,8 +762,8 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn get_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
question_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
let server = self.get_server();
|
||||
|
@ -771,23 +775,22 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn stream_complete(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
params: CompleteTextParams,
|
||||
ai_model: Option<AIModel>,
|
||||
) -> Result<StreamComplete, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let server = self.get_server()?;
|
||||
server
|
||||
.chat_service()
|
||||
.stream_complete(&workspace_id, params, ai_model)
|
||||
.stream_complete(workspace_id, params, ai_model)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn embed_file(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
file_path: &Path,
|
||||
chat_id: &str,
|
||||
chat_id: &Uuid,
|
||||
metadata: Option<HashMap<String, Value>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
|
@ -797,7 +800,7 @@ impl ChatCloudService for ServerProvider {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn get_local_ai_config(&self, workspace_id: &str) -> Result<LocalAIConfig, FlowyError> {
|
||||
async fn get_local_ai_config(&self, workspace_id: &Uuid) -> Result<LocalAIConfig, FlowyError> {
|
||||
self
|
||||
.get_server()?
|
||||
.chat_service()
|
||||
|
@ -807,7 +810,7 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn get_workspace_plan(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<SubscriptionPlan>, FlowyError> {
|
||||
self
|
||||
.get_server()?
|
||||
|
@ -818,8 +821,8 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn get_chat_settings(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<ChatSettings, FlowyError> {
|
||||
self
|
||||
.get_server()?
|
||||
|
@ -830,8 +833,8 @@ impl ChatCloudService for ServerProvider {
|
|||
|
||||
async fn update_chat_settings(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
params: UpdateChatParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
|
@ -841,7 +844,7 @@ impl ChatCloudService for ServerProvider {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn get_available_models(&self, workspace_id: &str) -> Result<ModelList, FlowyError> {
|
||||
async fn get_available_models(&self, workspace_id: &Uuid) -> Result<ModelList, FlowyError> {
|
||||
self
|
||||
.get_server()?
|
||||
.chat_service()
|
||||
|
@ -849,7 +852,7 @@ impl ChatCloudService for ServerProvider {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn get_workspace_default_model(&self, workspace_id: &str) -> Result<String, FlowyError> {
|
||||
async fn get_workspace_default_model(&self, workspace_id: &Uuid) -> Result<String, FlowyError> {
|
||||
self
|
||||
.get_server()?
|
||||
.chat_service()
|
||||
|
@ -862,7 +865,7 @@ impl ChatCloudService for ServerProvider {
|
|||
impl SearchCloudService for ServerProvider {
|
||||
async fn document_search(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
query: String,
|
||||
) -> Result<Vec<SearchDocumentResponseItem>, FlowyError> {
|
||||
let server = self.get_server()?;
|
||||
|
|
|
@ -13,6 +13,7 @@ use collab_integrate::collab_builder::WorkspaceCollabIntegrate;
|
|||
use lib_infra::util::timestamp;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::debug;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct SnapshotDBImpl(pub Weak<AuthenticateUser>);
|
||||
|
||||
|
@ -222,12 +223,12 @@ impl WorkspaceCollabIntegrateImpl {
|
|||
}
|
||||
|
||||
impl WorkspaceCollabIntegrate for WorkspaceCollabIntegrateImpl {
|
||||
fn workspace_id(&self) -> Result<String, anyhow::Error> {
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError> {
|
||||
let workspace_id = self.upgrade_user()?.workspace_id()?;
|
||||
Ok(workspace_id)
|
||||
}
|
||||
|
||||
fn device_id(&self) -> Result<String, anyhow::Error> {
|
||||
fn device_id(&self) -> Result<String, FlowyError> {
|
||||
Ok(self.upgrade_user()?.user_config.device_id.clone())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use lib_infra::async_trait::async_trait;
|
|||
use lib_infra::priority_task::TaskDispatcher;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct DatabaseDepsResolver();
|
||||
|
||||
|
@ -47,41 +48,41 @@ struct DatabaseAIServiceMiddleware {
|
|||
impl DatabaseAIService for DatabaseAIServiceMiddleware {
|
||||
async fn summary_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
workspace_id: &Uuid,
|
||||
object_id: &Uuid,
|
||||
_summary_row: SummaryRowContent,
|
||||
) -> Result<String, FlowyError> {
|
||||
if self.ai_manager.local_ai.is_running() {
|
||||
self
|
||||
.ai_manager
|
||||
.local_ai
|
||||
.summary_database_row(summary_row)
|
||||
.summary_database_row(_summary_row)
|
||||
.await
|
||||
.map_err(|err| FlowyError::local_ai().with_context(err))
|
||||
} else {
|
||||
self
|
||||
.ai_service
|
||||
.summary_database_row(workspace_id, object_id, summary_row)
|
||||
.summary_database_row(workspace_id, object_id, _summary_row)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
async fn translate_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
translate_row: TranslateRowContent,
|
||||
language: &str,
|
||||
_workspace_id: &Uuid,
|
||||
_translate_row: TranslateRowContent,
|
||||
_language: &str,
|
||||
) -> Result<TranslateRowResponse, FlowyError> {
|
||||
if self.ai_manager.local_ai.is_running() {
|
||||
let data = LocalAITranslateRowData {
|
||||
cells: translate_row
|
||||
cells: _translate_row
|
||||
.into_iter()
|
||||
.map(|row| LocalAITranslateItem {
|
||||
title: row.title,
|
||||
content: row.content,
|
||||
})
|
||||
.collect(),
|
||||
language: language.to_string(),
|
||||
language: _language.to_string(),
|
||||
include_header: false,
|
||||
};
|
||||
let resp = self
|
||||
|
@ -95,7 +96,7 @@ impl DatabaseAIService for DatabaseAIServiceMiddleware {
|
|||
} else {
|
||||
self
|
||||
.ai_service
|
||||
.translate_database_row(workspace_id, translate_row, language)
|
||||
.translate_database_row(_workspace_id, _translate_row, _language)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
@ -121,11 +122,11 @@ impl DatabaseUser for DatabaseUserImpl {
|
|||
self.upgrade_user()?.get_collab_db(uid)
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
|
||||
fn workspace_database_object_id(&self) -> Result<String, FlowyError> {
|
||||
fn workspace_database_object_id(&self) -> Result<Uuid, FlowyError> {
|
||||
self.upgrade_user()?.workspace_database_object_id()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::sync::{Arc, Weak};
|
||||
|
||||
use uuid::Uuid;
|
||||
use crate::deps_resolve::CollabSnapshotSql;
|
||||
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use collab_integrate::CollabKVDB;
|
||||
|
@ -97,7 +97,7 @@ impl DocumentUserService for DocumentUserImpl {
|
|||
.device_id()
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError> {
|
||||
self
|
||||
.0
|
||||
.upgrade()
|
||||
|
|
|
@ -4,6 +4,7 @@ use flowy_storage::manager::{StorageManager, StorageUserService};
|
|||
use flowy_storage_pub::cloud::StorageCloudService;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
use std::sync::{Arc, Weak};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct FileStorageResolver;
|
||||
|
||||
|
@ -40,7 +41,7 @@ impl StorageUserService for FileStorageServiceImpl {
|
|||
self.upgrade_user()?.user_id()
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use flowy_folder::share::ImportType;
|
|||
use flowy_folder::view_operation::{FolderOperationHandler, ImportedData};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct ChatFolderOperation(pub Arc<AIManager>);
|
||||
|
||||
|
@ -17,19 +18,19 @@ impl FolderOperationHandler for ChatFolderOperation {
|
|||
"ChatFolderOperationHandler"
|
||||
}
|
||||
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
async fn open_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self.0.open_chat(view_id).await
|
||||
}
|
||||
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
async fn close_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self.0.close_chat(view_id).await
|
||||
}
|
||||
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
async fn delete_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self.0.delete_chat(view_id).await
|
||||
}
|
||||
|
||||
async fn duplicate_view(&self, _view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
async fn duplicate_view(&self, view_id: &Uuid) -> Result<Bytes, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
|
||||
|
@ -44,10 +45,10 @@ impl FolderOperationHandler for ChatFolderOperation {
|
|||
async fn create_default_view(
|
||||
&self,
|
||||
user_id: i64,
|
||||
parent_view_id: &str,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
_layout: ViewLayout,
|
||||
parent_view_id: &Uuid,
|
||||
view_id: &Uuid,
|
||||
name: &str,
|
||||
layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
.0
|
||||
|
@ -58,11 +59,11 @@ impl FolderOperationHandler for ChatFolderOperation {
|
|||
|
||||
async fn import_from_bytes(
|
||||
&self,
|
||||
_uid: i64,
|
||||
_view_id: &str,
|
||||
_name: &str,
|
||||
_import_type: ImportType,
|
||||
_bytes: Vec<u8>,
|
||||
uid: i64,
|
||||
view_id: &Uuid,
|
||||
name: &str,
|
||||
import_type: ImportType,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
|
|
|
@ -19,23 +19,31 @@ use lib_infra::async_trait::async_trait;
|
|||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct DatabaseFolderOperation(pub Arc<DatabaseManager>);
|
||||
|
||||
#[async_trait]
|
||||
impl FolderOperationHandler for DatabaseFolderOperation {
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
async fn open_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self.0.open_database_view(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.close_database_view(view_id).await?;
|
||||
async fn close_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self
|
||||
.0
|
||||
.close_database_view(view_id.to_string().as_str())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
match self.0.delete_database_view(view_id).await {
|
||||
async fn delete_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
match self
|
||||
.0
|
||||
.delete_database_view(view_id.to_string().as_str())
|
||||
.await
|
||||
{
|
||||
Ok(_) => tracing::trace!("Delete database view: {}", view_id),
|
||||
Err(e) => tracing::error!("🔴delete database failed: {}", e),
|
||||
}
|
||||
|
@ -44,19 +52,23 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
|
||||
async fn gather_publish_encode_collab(
|
||||
&self,
|
||||
user: &Arc<dyn FolderUser>,
|
||||
view_id: &str,
|
||||
_user: &Arc<dyn FolderUser>,
|
||||
view_id: &Uuid,
|
||||
) -> Result<GatherEncodedCollab, FlowyError> {
|
||||
let workspace_id = user.workspace_id()?;
|
||||
let workspace_id = _user.workspace_id()?;
|
||||
let view_id_str = view_id.to_string();
|
||||
// get the collab_object_id for the database.
|
||||
//
|
||||
// the collab object_id for the database is not the view_id,
|
||||
// we should use the view_id to get the database_id
|
||||
let oid = self.0.get_database_id_with_view_id(view_id).await?;
|
||||
let row_oids = self.0.get_database_row_ids_with_view_id(view_id).await?;
|
||||
let oid = self.0.get_database_id_with_view_id(&view_id_str).await?;
|
||||
let row_oids = self
|
||||
.0
|
||||
.get_database_row_ids_with_view_id(&view_id_str)
|
||||
.await?;
|
||||
let row_metas = self
|
||||
.0
|
||||
.get_database_row_metas_with_view_id(view_id, row_oids.clone())
|
||||
.get_database_row_metas_with_view_id(&view_id, row_oids.clone())
|
||||
.await?;
|
||||
let row_document_ids = row_metas
|
||||
.iter()
|
||||
|
@ -68,12 +80,12 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
.collect::<Vec<_>>();
|
||||
let database_metas = self.0.get_all_databases_meta().await;
|
||||
|
||||
let uid = user
|
||||
let uid = _user
|
||||
.user_id()
|
||||
.map_err(|e| e.with_context("unable to get the uid: {}"))?;
|
||||
|
||||
// get the collab db
|
||||
let collab_db = user
|
||||
let collab_db = _user
|
||||
.collab_db(uid)
|
||||
.map_err(|e| e.with_context("unable to get the collab"))?;
|
||||
let collab_db = collab_db.upgrade().ok_or_else(|| {
|
||||
|
@ -84,7 +96,7 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let collab_read_txn = collab_db.read_txn();
|
||||
let database_collab = load_collab_by_object_id(uid, &collab_read_txn, &workspace_id, &oid)
|
||||
let database_collab = load_collab_by_object_id(uid, &collab_read_txn, &workspace_id.to_string(), &oid)
|
||||
.map_err(|e| {
|
||||
FlowyError::internal().with_context(format!("load database collab failed: {}", e))
|
||||
})?;
|
||||
|
@ -97,7 +109,7 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
})?;
|
||||
|
||||
let database_row_encoded_collabs =
|
||||
load_collab_by_object_ids(uid, &workspace_id, &collab_read_txn, &row_oids)
|
||||
load_collab_by_object_ids(uid, &workspace_id.to_string(), &collab_read_txn, &row_oids)
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|(oid, collab)| {
|
||||
|
@ -123,7 +135,7 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let database_row_document_encoded_collabs =
|
||||
load_collab_by_object_ids(uid, &workspace_id, &collab_read_txn, &row_document_ids)
|
||||
load_collab_by_object_ids(uid, &workspace_id.to_string(), &collab_read_txn, &row_document_ids)
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|(oid, collab)| {
|
||||
|
@ -147,7 +159,7 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
.await?
|
||||
}
|
||||
|
||||
async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
async fn duplicate_view(&self, view_id: &Uuid) -> Result<Bytes, FlowyError> {
|
||||
Ok(Bytes::from(view_id.to_string()))
|
||||
}
|
||||
|
||||
|
@ -166,14 +178,14 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
String::from_utf8(data.to_vec()).map_err(|_| FlowyError::invalid_data())?;
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.duplicate_database(&duplicated_view_id, ¶ms.view_id)
|
||||
.duplicate_database(&duplicated_view_id, ¶ms.view_id.to_string())
|
||||
.await?;
|
||||
Ok(Some(encoded_collab))
|
||||
},
|
||||
ViewData::Data(data) => {
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.create_database_with_data(¶ms.view_id, data.to_vec())
|
||||
.create_database_with_data(¶ms.view_id.to_string(), data.to_vec())
|
||||
.await?;
|
||||
Ok(Some(encoded_collab))
|
||||
},
|
||||
|
@ -212,17 +224,18 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
/// these references views.
|
||||
async fn create_default_view(
|
||||
&self,
|
||||
_user_id: i64,
|
||||
_parent_view_id: &str,
|
||||
view_id: &str,
|
||||
user_id: i64,
|
||||
parent_view_id: &Uuid,
|
||||
view_id: &Uuid,
|
||||
name: &str,
|
||||
layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
let name = name.to_string();
|
||||
let view_id = view_id.to_string();
|
||||
let data = match layout {
|
||||
ViewLayout::Grid => make_default_grid(view_id, &name),
|
||||
ViewLayout::Board => make_default_board(view_id, &name),
|
||||
ViewLayout::Calendar => make_default_calendar(view_id, &name),
|
||||
ViewLayout::Grid => make_default_grid(&view_id, &name),
|
||||
ViewLayout::Board => make_default_board(&view_id, &name),
|
||||
ViewLayout::Calendar => make_default_calendar(&view_id, &name),
|
||||
ViewLayout::Document | ViewLayout::Chat => {
|
||||
return Err(
|
||||
FlowyError::internal().with_context(format!("Can't handle {:?} layout type", layout)),
|
||||
|
@ -244,9 +257,9 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
|||
|
||||
async fn import_from_bytes(
|
||||
&self,
|
||||
_uid: i64,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
uid: i64,
|
||||
view_id: &Uuid,
|
||||
name: &str,
|
||||
import_type: ImportType,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
|
|
|
@ -17,8 +17,10 @@ use flowy_folder::view_operation::{
|
|||
use lib_dispatch::prelude::ToBytes;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct DocumentFolderOperation(pub Arc<DocumentManager>);
|
||||
#[async_trait]
|
||||
|
@ -33,6 +35,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
|||
workspace_view_builder: Arc<RwLock<NestedViewBuilder>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = self.0.clone();
|
||||
|
||||
let mut write_guard = workspace_view_builder.write().await;
|
||||
// Create a view named "Getting started" with an icon ⭐️ and the built-in README data.
|
||||
// Don't modify this code unless you know what you are doing.
|
||||
|
@ -45,8 +48,9 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
|||
// create a empty document
|
||||
let json_str = include_str!("../../../assets/read_me.json");
|
||||
let document_pb = JsonToDocumentParser::json_str_to_document(json_str).unwrap();
|
||||
let view_id = Uuid::from_str(&view.view.id).unwrap();
|
||||
manager
|
||||
.create_document(uid, &view.view.id, Some(document_pb.into()))
|
||||
.create_document(uid, &view_id, Some(document_pb.into()))
|
||||
.await
|
||||
.unwrap();
|
||||
view
|
||||
|
@ -55,18 +59,18 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
async fn open_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self.0.open_document(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Close the document view.
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
async fn close_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self.0.close_document(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
async fn delete_view(&self, view_id: &Uuid) -> Result<(), FlowyError> {
|
||||
match self.0.delete_document(view_id).await {
|
||||
Ok(_) => tracing::trace!("Delete document: {}", view_id),
|
||||
Err(e) => tracing::error!("🔴delete document failed: {}", e),
|
||||
|
@ -74,7 +78,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
async fn duplicate_view(&self, view_id: &Uuid) -> Result<Bytes, FlowyError> {
|
||||
let data: DocumentDataPB = self.0.get_document_data(view_id).await?.into();
|
||||
let data_bytes = data.into_bytes().map_err(|_| FlowyError::invalid_data())?;
|
||||
Ok(data_bytes)
|
||||
|
@ -83,10 +87,11 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
|||
async fn gather_publish_encode_collab(
|
||||
&self,
|
||||
user: &Arc<dyn FolderUser>,
|
||||
view_id: &str,
|
||||
view_id: &Uuid,
|
||||
) -> Result<GatherEncodedCollab, FlowyError> {
|
||||
let encoded_collab =
|
||||
get_encoded_collab_v1_from_disk(user, view_id, CollabType::Document).await?;
|
||||
get_encoded_collab_v1_from_disk(user, view_id.to_string().as_str(), CollabType::Document)
|
||||
.await?;
|
||||
Ok(GatherEncodedCollab::Document(encoded_collab))
|
||||
}
|
||||
|
||||
|
@ -112,9 +117,9 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
|||
async fn create_default_view(
|
||||
&self,
|
||||
user_id: i64,
|
||||
_parent_view_id: &str,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
parent_view_id: &Uuid,
|
||||
view_id: &Uuid,
|
||||
name: &str,
|
||||
layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
debug_assert_eq!(layout, ViewLayout::Document);
|
||||
|
@ -133,9 +138,9 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
|||
async fn import_from_bytes(
|
||||
&self,
|
||||
uid: i64,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
_import_type: ImportType,
|
||||
view_id: &Uuid,
|
||||
name: &str,
|
||||
import_type: ImportType,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
let data = DocumentDataPB::try_from(Bytes::from(bytes))?;
|
||||
|
|
|
@ -17,6 +17,7 @@ use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
|||
use flowy_sqlite::kv::KVStorePreferences;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
use flowy_user::services::data_import::load_collab_by_object_id;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use crate::deps_resolve::folder_deps::folder_deps_chat_impl::ChatFolderOperation;
|
||||
|
@ -25,6 +26,7 @@ use crate::deps_resolve::folder_deps::folder_deps_doc_impl::DocumentFolderOperat
|
|||
use collab_plugins::local_storage::kv::KVTransactionDB;
|
||||
use flowy_folder_pub::query::{FolderQueryService, FolderService, FolderViewEdit, QueryCollab};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct FolderDepsResolver();
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -89,7 +91,7 @@ impl FolderUser for FolderUserImpl {
|
|||
self.upgrade_user()?.user_id()
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
|
||||
|
@ -97,8 +99,10 @@ impl FolderUser for FolderUserImpl {
|
|||
self.upgrade_user()?.get_collab_db(uid)
|
||||
}
|
||||
|
||||
fn is_folder_exist_on_disk(&self, uid: i64, workspace_id: &str) -> FlowyResult<bool> {
|
||||
self.upgrade_user()?.is_collab_on_disk(uid, workspace_id)
|
||||
fn is_folder_exist_on_disk(&self, uid: i64, workspace_id: &Uuid) -> FlowyResult<bool> {
|
||||
self
|
||||
.upgrade_user()?
|
||||
.is_collab_on_disk(uid, workspace_id.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,13 +128,13 @@ impl FolderServiceImpl {
|
|||
|
||||
#[async_trait]
|
||||
impl FolderViewEdit for FolderServiceImpl {
|
||||
async fn set_view_title_if_empty(&self, view_id: &str, title: &str) -> FlowyResult<()> {
|
||||
async fn set_view_title_if_empty(&self, view_id: &Uuid, title: &str) -> FlowyResult<()> {
|
||||
if title.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(folder_manager) = self.folder_manager.upgrade() {
|
||||
if let Ok(view) = folder_manager.get_view(view_id).await {
|
||||
if let Ok(view) = folder_manager.get_view(view_id.to_string().as_str()).await {
|
||||
if view.name.is_empty() {
|
||||
let title = if title.len() > 50 {
|
||||
title.chars().take(50).collect()
|
||||
|
@ -160,22 +164,25 @@ impl FolderViewEdit for FolderServiceImpl {
|
|||
impl FolderQueryService for FolderServiceImpl {
|
||||
async fn get_surrounding_view_ids_with_view_layout(
|
||||
&self,
|
||||
parent_view_id: &str,
|
||||
parent_view_id: &Uuid,
|
||||
view_layout: ViewLayout,
|
||||
) -> Vec<String> {
|
||||
) -> Vec<Uuid> {
|
||||
let folder_manager = match self.folder_manager.upgrade() {
|
||||
Some(folder_manager) => folder_manager,
|
||||
None => return vec![],
|
||||
};
|
||||
|
||||
if let Ok(view) = folder_manager.get_view(parent_view_id).await {
|
||||
if let Ok(view) = folder_manager
|
||||
.get_view(parent_view_id.to_string().as_str())
|
||||
.await
|
||||
{
|
||||
if view.space_info().is_some() {
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
|
||||
match folder_manager
|
||||
.get_untrashed_views_belong_to(parent_view_id)
|
||||
.get_untrashed_views_belong_to(parent_view_id.to_string().as_str())
|
||||
.await
|
||||
{
|
||||
Ok(views) => {
|
||||
|
@ -183,23 +190,24 @@ impl FolderQueryService for FolderServiceImpl {
|
|||
.into_iter()
|
||||
.filter_map(|child| {
|
||||
if child.layout == view_layout {
|
||||
Some(child.id.clone())
|
||||
Uuid::from_str(&child.id).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
children.push(parent_view_id.to_string());
|
||||
children.push(parent_view_id.clone());
|
||||
children
|
||||
},
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_collab(&self, object_id: &str, collab_type: CollabType) -> Option<QueryCollab> {
|
||||
let encode_collab = get_encoded_collab_v1_from_disk(&self.user, object_id, collab_type)
|
||||
.await
|
||||
.ok();
|
||||
async fn get_collab(&self, object_id: &Uuid, collab_type: CollabType) -> Option<QueryCollab> {
|
||||
let encode_collab =
|
||||
get_encoded_collab_v1_from_disk(&self.user, object_id.to_string().as_str(), collab_type)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
encode_collab.map(|encoded_collab| QueryCollab {
|
||||
collab_type,
|
||||
|
@ -229,8 +237,8 @@ async fn get_encoded_collab_v1_from_disk(
|
|||
)
|
||||
})?;
|
||||
let collab_read_txn = collab_db.read_txn();
|
||||
let collab =
|
||||
load_collab_by_object_id(uid, &collab_read_txn, &workspace_id, view_id).map_err(|e| {
|
||||
let collab = load_collab_by_object_id(uid, &collab_read_txn, &workspace_id.to_string(), view_id)
|
||||
.map_err(|e| {
|
||||
FlowyError::internal().with_context(format!("load document collab failed: {}", e))
|
||||
})?;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ use lib_infra::async_trait::async_trait;
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tracing::info;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct UserDepsResolver();
|
||||
|
||||
|
@ -81,7 +82,7 @@ impl UserWorkspaceService for UserWorkspaceServiceImpl {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn did_delete_workspace(&self, workspace_id: String) -> FlowyResult<()> {
|
||||
fn did_delete_workspace(&self, workspace_id: &Uuid) -> FlowyResult<()> {
|
||||
// The remove_indices_for_workspace should not block the deletion of the workspace
|
||||
// Log the error and continue
|
||||
if let Err(err) = self
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#![allow(unused_doc_comments)]
|
||||
|
||||
use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
||||
use flowy_search::services::manager::SearchManager;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
use sysinfo::System;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{debug, error, event, info, instrument};
|
||||
|
||||
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabPluginProviderType};
|
||||
use flowy_ai::ai_manager::AIManager;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document::manager::DocumentManager;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_folder::manager::FolderManager;
|
||||
use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
||||
use flowy_search::services::manager::SearchManager;
|
||||
use flowy_server::af_cloud::define::ServerUser;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
use sysinfo::System;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{debug, error, event, info, instrument};
|
||||
use uuid::Uuid;
|
||||
|
||||
use flowy_sqlite::kv::KVStorePreferences;
|
||||
use flowy_storage::manager::StorageManager;
|
||||
|
@ -329,7 +329,7 @@ impl ServerUserImpl {
|
|||
}
|
||||
}
|
||||
impl ServerUser for ServerUserImpl {
|
||||
fn workspace_id(&self) -> FlowyResult<String> {
|
||||
fn workspace_id(&self) -> FlowyResult<Uuid> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
|||
_device_id: &str,
|
||||
authenticator: &Authenticator,
|
||||
) -> FlowyResult<()> {
|
||||
let workspace_id = user_workspace.workspace_id()?;
|
||||
self
|
||||
.server_provider
|
||||
.set_user_authenticator(user_authenticator);
|
||||
|
@ -74,7 +75,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
|||
.folder_manager
|
||||
.initialize(
|
||||
user_id,
|
||||
&user_workspace.id,
|
||||
&workspace_id,
|
||||
FolderInitDataSource::LocalDisk {
|
||||
create_if_not_exist: false,
|
||||
},
|
||||
|
@ -140,6 +141,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
|||
user_workspace,
|
||||
device_id
|
||||
);
|
||||
let workspace_id = user_workspace.workspace_id()?;
|
||||
|
||||
// In the current implementation, when a user signs up for AppFlowy Cloud, a default workspace
|
||||
// is automatically created for them. However, for users who sign up through Supabase, the creation
|
||||
|
@ -149,10 +151,10 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
|||
.folder_manager
|
||||
.cloud_service
|
||||
.get_folder_doc_state(
|
||||
&user_workspace.id,
|
||||
&workspace_id,
|
||||
user_profile.uid,
|
||||
CollabType::Folder,
|
||||
&user_workspace.id,
|
||||
&workspace_id,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
@ -179,7 +181,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
|||
&user_profile.token,
|
||||
is_new_user,
|
||||
data_source,
|
||||
&user_workspace.id,
|
||||
&workspace_id,
|
||||
)
|
||||
.await
|
||||
.context("FolderManager error")?;
|
||||
|
|
|
@ -9,6 +9,6 @@ edition = "2021"
|
|||
lib-infra = { workspace = true }
|
||||
collab-entity = { workspace = true }
|
||||
collab = { workspace = true }
|
||||
anyhow.workspace = true
|
||||
client-api = { workspace = true }
|
||||
flowy-error = { workspace = true }
|
||||
flowy-error = { workspace = true }
|
||||
uuid.workspace = true
|
|
@ -4,8 +4,9 @@ use collab_entity::CollabType;
|
|||
use flowy_error::FlowyError;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub type EncodeCollabByOid = HashMap<String, EncodedCollab>;
|
||||
pub type EncodeCollabByOid = HashMap<Uuid, EncodedCollab>;
|
||||
pub type SummaryRowContent = HashMap<String, String>;
|
||||
pub type TranslateRowContent = Vec<TranslateItem>;
|
||||
|
||||
|
@ -13,8 +14,8 @@ pub type TranslateRowContent = Vec<TranslateItem>;
|
|||
pub trait DatabaseAIService: Send + Sync {
|
||||
async fn summary_database_row(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_object_id: &str,
|
||||
_workspace_id: &Uuid,
|
||||
_object_id: &Uuid,
|
||||
_summary_row: SummaryRowContent,
|
||||
) -> Result<String, FlowyError> {
|
||||
Ok("".to_string())
|
||||
|
@ -22,7 +23,7 @@ pub trait DatabaseAIService: Send + Sync {
|
|||
|
||||
async fn translate_database_row(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_workspace_id: &Uuid,
|
||||
_translate_row: TranslateRowContent,
|
||||
_language: &str,
|
||||
) -> Result<TranslateRowResponse, FlowyError> {
|
||||
|
@ -41,29 +42,29 @@ pub trait DatabaseAIService: Send + Sync {
|
|||
pub trait DatabaseCloudService: Send + Sync {
|
||||
async fn get_database_encode_collab(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError>;
|
||||
|
||||
async fn create_database_encode_collab(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn batch_get_database_encode_collab(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
object_ids: Vec<Uuid>,
|
||||
object_ty: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<EncodeCollabByOid, FlowyError>;
|
||||
|
||||
async fn get_database_collab_object_snapshots(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
limit: usize,
|
||||
) -> Result<Vec<DatabaseSnapshot>, FlowyError>;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ strum_macros = "0.25"
|
|||
validator = { workspace = true, features = ["derive"] }
|
||||
tokio-util.workspace = true
|
||||
moka = { version = "0.12.8", features = ["future"] }
|
||||
uuid.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
event-integration-test = { path = "../event-integration-test", default-features = false }
|
||||
|
|
|
@ -1261,7 +1261,7 @@ pub(crate) async fn summarize_row_handler(
|
|||
let (tx, rx) = oneshot::channel();
|
||||
tokio::spawn(async move {
|
||||
let result = manager
|
||||
.summarize_row(data.view_id, row_id, data.field_id)
|
||||
.summarize_row(&data.view_id, row_id, data.field_id)
|
||||
.await;
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
|
@ -1280,7 +1280,7 @@ pub(crate) async fn translate_row_handler(
|
|||
let (tx, rx) = oneshot::channel();
|
||||
tokio::spawn(async move {
|
||||
let result = manager
|
||||
.translate_row(data.view_id, row_id, data.field_id)
|
||||
.translate_row(&data.view_id, row_id, data.field_id)
|
||||
.await;
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
|
|
|
@ -20,6 +20,7 @@ use collab_entity::{CollabObject, CollabType, EncodedCollab};
|
|||
use collab_plugins::local_storage::kv::KVTransactionDB;
|
||||
use rayon::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
use tokio::sync::Mutex;
|
||||
|
@ -42,12 +43,13 @@ use crate::services::database_view::DatabaseLayoutDepsResolver;
|
|||
use crate::services::field_settings::default_field_settings_by_layout_map;
|
||||
use crate::services::share::csv::{CSVFormat, CSVImporter, ImportResult};
|
||||
use tokio::sync::RwLock as TokioRwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub trait DatabaseUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_database_object_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError>;
|
||||
fn workspace_database_object_id(&self) -> Result<Uuid, FlowyError>;
|
||||
}
|
||||
|
||||
pub(crate) type DatabaseEditorMap = HashMap<String, Arc<DatabaseEditor>>;
|
||||
|
@ -110,7 +112,7 @@ impl DatabaseManager {
|
|||
let workspace_database_object_id = self.user.workspace_database_object_id()?;
|
||||
let workspace_database_collab = collab_service
|
||||
.build_collab(
|
||||
workspace_database_object_id.as_str(),
|
||||
workspace_database_object_id.to_string().as_str(),
|
||||
CollabType::WorkspaceDatabase,
|
||||
None,
|
||||
)
|
||||
|
@ -189,8 +191,10 @@ impl DatabaseManager {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn encode_database(&self, view_id: &str) -> FlowyResult<EncodedDatabase> {
|
||||
let editor = self.get_database_editor_with_view_id(view_id).await?;
|
||||
pub async fn encode_database(&self, view_id: &Uuid) -> FlowyResult<EncodedDatabase> {
|
||||
let editor = self
|
||||
.get_database_editor_with_view_id(view_id.to_string().as_str())
|
||||
.await?;
|
||||
let collabs = editor
|
||||
.database
|
||||
.read()
|
||||
|
@ -207,10 +211,12 @@ impl DatabaseManager {
|
|||
|
||||
pub async fn get_database_row_metas_with_view_id(
|
||||
&self,
|
||||
view_id: &str,
|
||||
view_id: &Uuid,
|
||||
row_ids: Vec<RowId>,
|
||||
) -> FlowyResult<Vec<RowMetaPB>> {
|
||||
let database = self.get_database_editor_with_view_id(view_id).await?;
|
||||
let database = self
|
||||
.get_database_editor_with_view_id(view_id.to_string().as_str())
|
||||
.await?;
|
||||
let view_id = view_id.to_string();
|
||||
let mut row_metas: Vec<RowMetaPB> = vec![];
|
||||
for row_id in row_ids {
|
||||
|
@ -275,11 +281,11 @@ impl DatabaseManager {
|
|||
|
||||
/// Open the database view
|
||||
#[instrument(level = "trace", skip_all, err)]
|
||||
pub async fn open_database_view<T: AsRef<str>>(&self, view_id: T) -> FlowyResult<()> {
|
||||
let view_id = view_id.as_ref();
|
||||
pub async fn open_database_view(&self, view_id: &Uuid) -> FlowyResult<()> {
|
||||
let view_id = view_id.to_string();
|
||||
let lock = self.workspace_database()?;
|
||||
let workspace_database = lock.read().await;
|
||||
let result = workspace_database.get_database_id_with_view_id(view_id);
|
||||
let result = workspace_database.get_database_id_with_view_id(&view_id);
|
||||
drop(workspace_database);
|
||||
|
||||
if let Some(database_id) = result {
|
||||
|
@ -292,8 +298,7 @@ impl DatabaseManager {
|
|||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all, err)]
|
||||
pub async fn close_database_view<T: AsRef<str>>(&self, view_id: T) -> FlowyResult<()> {
|
||||
let view_id = view_id.as_ref();
|
||||
pub async fn close_database_view(&self, view_id: &str) -> FlowyResult<()> {
|
||||
let lock = self.workspace_database()?;
|
||||
let workspace_database = lock.read().await;
|
||||
let database_id = workspace_database.get_database_id_with_view_id(view_id);
|
||||
|
@ -518,7 +523,9 @@ impl DatabaseManager {
|
|||
layout: DatabaseLayoutPB,
|
||||
) -> FlowyResult<()> {
|
||||
let database = self.get_database_editor_with_view_id(view_id).await?;
|
||||
database.update_view_layout(view_id, layout.into()).await
|
||||
database
|
||||
.update_view_layout(view_id.to_string().as_str(), layout.into())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_database_snapshots(
|
||||
|
@ -526,7 +533,7 @@ impl DatabaseManager {
|
|||
view_id: &str,
|
||||
limit: usize,
|
||||
) -> FlowyResult<Vec<DatabaseSnapshotPB>> {
|
||||
let database_id = self.get_database_id_with_view_id(view_id).await?;
|
||||
let database_id = Uuid::from_str(&self.get_database_id_with_view_id(view_id).await?)?;
|
||||
let snapshots = self
|
||||
.cloud_service
|
||||
.get_database_collab_object_snapshots(&database_id, limit)
|
||||
|
@ -553,11 +560,11 @@ impl DatabaseManager {
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn summarize_row(
|
||||
&self,
|
||||
view_id: String,
|
||||
view_id: &str,
|
||||
row_id: RowId,
|
||||
field_id: String,
|
||||
) -> FlowyResult<()> {
|
||||
let database = self.get_database_editor_with_view_id(&view_id).await?;
|
||||
let database = self.get_database_editor_with_view_id(view_id).await?;
|
||||
let mut summary_row_content = SummaryRowContent::new();
|
||||
if let Some(row) = database.get_row(&view_id, &row_id).await {
|
||||
let fields = database.get_fields(&view_id, None).await;
|
||||
|
@ -583,7 +590,11 @@ impl DatabaseManager {
|
|||
);
|
||||
let response = self
|
||||
.ai_service
|
||||
.summary_database_row(&self.user.workspace_id()?, &row_id, summary_row_content)
|
||||
.summary_database_row(
|
||||
&self.user.workspace_id()?,
|
||||
&Uuid::from_str(&row_id)?,
|
||||
summary_row_content,
|
||||
)
|
||||
.await?;
|
||||
trace!("[AI]:summarize row response: {}", response);
|
||||
|
||||
|
@ -597,11 +608,12 @@ impl DatabaseManager {
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn translate_row(
|
||||
&self,
|
||||
view_id: String,
|
||||
view_id: &str,
|
||||
row_id: RowId,
|
||||
field_id: String,
|
||||
) -> FlowyResult<()> {
|
||||
let database = self.get_database_editor_with_view_id(&view_id).await?;
|
||||
let database = self.get_database_editor_with_view_id(view_id).await?;
|
||||
let view_id = view_id.to_string();
|
||||
let mut translate_row_content = TranslateRowContent::new();
|
||||
let mut language = "english".to_string();
|
||||
|
||||
|
@ -703,10 +715,13 @@ impl WorkspaceDatabaseCollabServiceImpl {
|
|||
|
||||
async fn get_encode_collab(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
object_ty: CollabType,
|
||||
) -> Result<Option<EncodedCollab>, DatabaseError> {
|
||||
let workspace_id = self.user.workspace_id().unwrap();
|
||||
let workspace_id = self
|
||||
.user
|
||||
.workspace_id()
|
||||
.map_err(|e| DatabaseError::Internal(e.into()))?;
|
||||
trace!("[Database]: fetch {}:{} from remote", object_id, object_ty);
|
||||
let encode_collab = self
|
||||
.cloud_service
|
||||
|
@ -718,7 +733,7 @@ impl WorkspaceDatabaseCollabServiceImpl {
|
|||
|
||||
async fn batch_get_encode_collab(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
object_ids: Vec<Uuid>,
|
||||
object_ty: CollabType,
|
||||
) -> Result<EncodeCollabByOid, DatabaseError> {
|
||||
let workspace_id = self
|
||||
|
@ -730,7 +745,13 @@ impl WorkspaceDatabaseCollabServiceImpl {
|
|||
.batch_get_database_encode_collab(object_ids, object_ty, &workspace_id)
|
||||
.await
|
||||
.map_err(|err| DatabaseError::Internal(err.into()))?;
|
||||
Ok(updates)
|
||||
|
||||
Ok(
|
||||
updates
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
fn collab_db(&self) -> Result<Weak<CollabKVDB>, DatabaseError> {
|
||||
|
@ -746,7 +767,7 @@ impl WorkspaceDatabaseCollabServiceImpl {
|
|||
|
||||
fn build_collab_object(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
object_type: CollabType,
|
||||
) -> Result<CollabObject, DatabaseError> {
|
||||
let uid = self
|
||||
|
@ -776,8 +797,12 @@ impl DatabaseCollabService for WorkspaceDatabaseCollabServiceImpl {
|
|||
collab_type: CollabType,
|
||||
encoded_collab: Option<(EncodedCollab, bool)>,
|
||||
) -> Result<Collab, DatabaseError> {
|
||||
let object = self.build_collab_object(object_id, collab_type)?;
|
||||
let data_source = if self.persistence.is_collab_exist(object_id) {
|
||||
let object_id = Uuid::parse_str(object_id)?;
|
||||
let object = self.build_collab_object(&object_id, collab_type)?;
|
||||
let data_source = if self
|
||||
.persistence
|
||||
.is_collab_exist(object_id.to_string().as_str())
|
||||
{
|
||||
trace!(
|
||||
"build collab: {}:{} from local encode collab",
|
||||
collab_type,
|
||||
|
@ -796,7 +821,7 @@ impl DatabaseCollabService for WorkspaceDatabaseCollabServiceImpl {
|
|||
object_id,
|
||||
encoded_collab.is_none(),
|
||||
);
|
||||
match self.get_encode_collab(object_id, collab_type).await {
|
||||
match self.get_encode_collab(&object_id, collab_type).await {
|
||||
Ok(Some(encode_collab)) => {
|
||||
info!(
|
||||
"build collab: {}:{} with remote encode collab, {} bytes",
|
||||
|
@ -837,12 +862,11 @@ impl DatabaseCollabService for WorkspaceDatabaseCollabServiceImpl {
|
|||
);
|
||||
self
|
||||
.persistence
|
||||
.save_collab(object_id, encoded_collab.clone())?;
|
||||
.save_collab(object_id.to_string().as_str(), encoded_collab.clone())?;
|
||||
|
||||
// TODO(nathan): cover database rows and other database collab type
|
||||
if matches!(collab_type, CollabType::Database) {
|
||||
if let Ok(workspace_id) = self.user.workspace_id() {
|
||||
let object_id = object_id.to_string();
|
||||
let cloned_encoded_collab = encoded_collab.clone();
|
||||
let cloud_service = self.cloud_service.clone();
|
||||
tokio::spawn(async move {
|
||||
|
@ -878,6 +902,7 @@ impl DatabaseCollabService for WorkspaceDatabaseCollabServiceImpl {
|
|||
if object_ids.is_empty() {
|
||||
return Ok(EncodeCollabByOid::new());
|
||||
}
|
||||
|
||||
let mut encoded_collab_by_id = EncodeCollabByOid::new();
|
||||
// 1. Collect local disk collabs into a HashMap
|
||||
let local_disk_encoded_collab: HashMap<String, EncodedCollab> = object_ids
|
||||
|
@ -900,6 +925,10 @@ impl DatabaseCollabService for WorkspaceDatabaseCollabServiceImpl {
|
|||
}
|
||||
|
||||
if !object_ids.is_empty() {
|
||||
let object_ids = object_ids
|
||||
.into_iter()
|
||||
.flat_map(|v| Uuid::from_str(&v).ok())
|
||||
.collect::<Vec<_>>();
|
||||
// 2. Fetch remaining collabs from remote
|
||||
let remote_collabs = self
|
||||
.batch_get_encode_collab(object_ids, collab_type)
|
||||
|
@ -927,7 +956,7 @@ pub struct DatabasePersistenceImpl {
|
|||
}
|
||||
|
||||
impl DatabasePersistenceImpl {
|
||||
fn workspace_id(&self) -> Result<String, DatabaseError> {
|
||||
fn workspace_id(&self) -> Result<Uuid, DatabaseError> {
|
||||
let workspace_id = self
|
||||
.user
|
||||
.workspace_id()
|
||||
|
@ -947,7 +976,7 @@ impl DatabaseCollabPersistenceService for DatabasePersistenceImpl {
|
|||
if let Ok((uid, Ok(Some(collab_db)))) = result {
|
||||
let object_id = collab.object_id().to_string();
|
||||
let db_read = collab_db.read_txn();
|
||||
if !db_read.is_exist(uid, &workspace_id, &object_id) {
|
||||
if !db_read.is_exist(uid, workspace_id.to_string().as_str(), &object_id) {
|
||||
trace!(
|
||||
"[Database]: collab:{} not exist in local storage",
|
||||
object_id
|
||||
|
@ -957,7 +986,12 @@ impl DatabaseCollabPersistenceService for DatabasePersistenceImpl {
|
|||
|
||||
trace!("[Database]: start loading collab:{} from disk", object_id);
|
||||
let mut txn = collab.transact_mut();
|
||||
match db_read.load_doc_with_txn(uid, &workspace_id, &object_id, &mut txn) {
|
||||
match db_read.load_doc_with_txn(
|
||||
uid,
|
||||
workspace_id.to_string().as_str(),
|
||||
&object_id,
|
||||
&mut txn,
|
||||
) {
|
||||
Ok(update_count) => {
|
||||
trace!(
|
||||
"[Database]: did load collab:{}, update_count:{}",
|
||||
|
@ -976,7 +1010,7 @@ impl DatabaseCollabPersistenceService for DatabasePersistenceImpl {
|
|||
}
|
||||
|
||||
fn get_encoded_collab(&self, object_id: &str, collab_type: CollabType) -> Option<EncodedCollab> {
|
||||
let workspace_id = self.user.workspace_id().ok()?;
|
||||
let workspace_id = self.user.workspace_id().ok()?.to_string();
|
||||
let uid = self.user.user_id().ok()?;
|
||||
let db = self.user.collab_db(uid).ok()?.upgrade()?;
|
||||
let read_txn = db.read_txn();
|
||||
|
@ -995,7 +1029,7 @@ impl DatabaseCollabPersistenceService for DatabasePersistenceImpl {
|
|||
}
|
||||
|
||||
fn delete_collab(&self, object_id: &str) -> Result<(), DatabaseError> {
|
||||
let workspace_id = self.workspace_id()?;
|
||||
let workspace_id = self.workspace_id()?.to_string();
|
||||
let uid = self
|
||||
.user
|
||||
.user_id()
|
||||
|
@ -1017,7 +1051,7 @@ impl DatabaseCollabPersistenceService for DatabasePersistenceImpl {
|
|||
object_id: &str,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let workspace_id = self.workspace_id()?;
|
||||
let workspace_id = self.workspace_id()?.to_string();
|
||||
let uid = self
|
||||
.user
|
||||
.user_id()
|
||||
|
@ -1051,7 +1085,7 @@ impl DatabaseCollabPersistenceService for DatabasePersistenceImpl {
|
|||
Ok(uid) => {
|
||||
if let Ok(Some(collab_db)) = self.user.collab_db(uid).map(|weak| weak.upgrade()) {
|
||||
let read_txn = collab_db.read_txn();
|
||||
return read_txn.is_exist(uid, workspace_id.as_str(), object_id);
|
||||
return read_txn.is_exist(uid, workspace_id.to_string().as_str(), object_id);
|
||||
}
|
||||
false
|
||||
},
|
||||
|
@ -1073,7 +1107,8 @@ impl DatabaseCollabPersistenceService for DatabasePersistenceImpl {
|
|||
let workspace_id = self
|
||||
.user
|
||||
.workspace_id()
|
||||
.map_err(|err| DatabaseError::Internal(err.into()))?;
|
||||
.map_err(|err| DatabaseError::Internal(err.into()))?
|
||||
.to_string();
|
||||
|
||||
if let Ok(Some(collab_db)) = self.user.collab_db(uid).map(|weak| weak.upgrade()) {
|
||||
let write_txn = collab_db.write_txn();
|
||||
|
|
|
@ -44,6 +44,7 @@ use lib_infra::box_any::BoxAny;
|
|||
use lib_infra::priority_task::TaskDispatcher;
|
||||
use lib_infra::util::timestamp;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
use tokio::select;
|
||||
|
@ -53,11 +54,12 @@ use tokio::sync::{broadcast, oneshot};
|
|||
use tokio::task::yield_now;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, error, event, info, instrument, trace, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
type OpenDatabaseResult = oneshot::Sender<FlowyResult<DatabasePB>>;
|
||||
|
||||
pub struct DatabaseEditor {
|
||||
database_id: String,
|
||||
database_id: Uuid,
|
||||
pub(crate) database: Arc<RwLock<Database>>,
|
||||
pub cell_cache: CellCache,
|
||||
pub(crate) database_views: Arc<DatabaseViews>,
|
||||
|
@ -117,6 +119,7 @@ impl DatabaseEditor {
|
|||
.await?,
|
||||
);
|
||||
|
||||
let database_id = Uuid::from_str(&database_id)?;
|
||||
let collab_object = collab_builder.collab_object(
|
||||
&user.workspace_id()?,
|
||||
user.user_id()?,
|
||||
|
@ -806,10 +809,11 @@ impl DatabaseEditor {
|
|||
let is_finalized = self.finalized_rows.get(row_id.as_str()).await.is_some();
|
||||
if !is_finalized {
|
||||
trace!("[Database]: finalize database row: {}", row_id);
|
||||
let row_id = Uuid::from_str(row_id.as_str())?;
|
||||
let collab_object = self.collab_builder.collab_object(
|
||||
&self.user.workspace_id()?,
|
||||
self.user.user_id()?,
|
||||
row_id,
|
||||
&row_id,
|
||||
CollabType::DatabaseRow,
|
||||
)?;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use futures::StreamExt;
|
|||
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, trace, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) async fn observe_sync_state(database_id: &str, database: &Arc<RwLock<Database>>) {
|
||||
let weak_database = Arc::downgrade(database);
|
||||
|
@ -112,7 +113,7 @@ pub(crate) async fn observe_field_change(database_id: &str, database: &Arc<RwLoc
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn observe_view_change(database_id: &str, database_editor: &Arc<DatabaseEditor>) {
|
||||
pub(crate) async fn observe_view_change(database_id: &Uuid, database_editor: &Arc<DatabaseEditor>) {
|
||||
let database_id = database_id.to_string();
|
||||
let weak_database_editor = Arc::downgrade(database_editor);
|
||||
let view_change = database_editor
|
||||
|
@ -289,7 +290,7 @@ async fn handle_did_update_row_orders(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn observe_block_event(database_id: &str, database_editor: &Arc<DatabaseEditor>) {
|
||||
pub(crate) async fn observe_block_event(database_id: &Uuid, database_editor: &Arc<DatabaseEditor>) {
|
||||
let database_id = database_id.to_string();
|
||||
let mut block_event_rx = database_editor
|
||||
.database
|
||||
|
|
|
@ -9,5 +9,5 @@ edition = "2021"
|
|||
lib-infra = { workspace = true }
|
||||
flowy-error = { workspace = true }
|
||||
collab-document = { workspace = true }
|
||||
anyhow.workspace = true
|
||||
collab = { workspace = true }
|
||||
collab = { workspace = true }
|
||||
uuid.workspace = true
|
|
@ -1,8 +1,8 @@
|
|||
use collab::entity::EncodedCollab;
|
||||
pub use collab_document::blocks::DocumentData;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// A trait for document cloud service.
|
||||
/// Each kind of server should implement this trait. Check out the [AppFlowyServerProvider] of
|
||||
|
@ -11,27 +11,27 @@ use lib_infra::async_trait::async_trait;
|
|||
pub trait DocumentCloudService: Send + Sync + 'static {
|
||||
async fn get_document_doc_state(
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError>;
|
||||
|
||||
async fn get_document_snapshots(
|
||||
&self,
|
||||
document_id: &str,
|
||||
document_id: &Uuid,
|
||||
limit: usize,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<DocumentSnapshot>, FlowyError>;
|
||||
|
||||
async fn get_document_data(
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<DocumentData>, FlowyError>;
|
||||
|
||||
async fn create_document_collab(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
document_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
document_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError>;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,10 @@ use collab::preclude::Collab;
|
|||
use collab_document::document::Document;
|
||||
use futures::StreamExt;
|
||||
use lib_infra::sync_trace;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub fn subscribe_document_changed(doc_id: &str, document: &mut Document) {
|
||||
let doc_id_clone_for_block_changed = doc_id.to_owned();
|
||||
pub fn subscribe_document_changed(doc_id: &Uuid, document: &mut Document) {
|
||||
let doc_id_clone_for_block_changed = doc_id.to_string();
|
||||
document.subscribe_block_changed("key", move |events, is_remote| {
|
||||
sync_trace!(
|
||||
"[Document] block changed in doc_id: {}, is_remote: {}, events: {:?}",
|
||||
|
@ -35,7 +36,7 @@ pub fn subscribe_document_changed(doc_id: &str, document: &mut Document) {
|
|||
);
|
||||
|
||||
document_notification_builder(
|
||||
&doc_id_clone_for_awareness_state,
|
||||
&doc_id_clone_for_awareness_state.to_string(),
|
||||
DocumentNotification::DidUpdateDocumentAwarenessState,
|
||||
)
|
||||
.payload::<DocumentAwarenessStatesPB>(events.into())
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use collab::core::collab_state::SyncState;
|
||||
use collab_document::{
|
||||
blocks::{json_str_to_hashmap, Block, BlockAction, DocumentData},
|
||||
|
@ -8,10 +6,12 @@ use collab_document::{
|
|||
DocumentAwarenessUser,
|
||||
},
|
||||
};
|
||||
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::ErrorCode;
|
||||
use lib_infra::validator_fn::{required_not_empty_str, required_valid_path};
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::parse::{NotEmptyStr, NotEmptyVec};
|
||||
|
@ -31,7 +31,7 @@ pub struct OpenDocumentPayloadPB {
|
|||
}
|
||||
|
||||
pub struct OpenDocumentParams {
|
||||
pub document_id: String,
|
||||
pub document_id: Uuid,
|
||||
}
|
||||
|
||||
impl TryInto<OpenDocumentParams> for OpenDocumentPayloadPB {
|
||||
|
@ -39,9 +39,9 @@ impl TryInto<OpenDocumentParams> for OpenDocumentPayloadPB {
|
|||
fn try_into(self) -> Result<OpenDocumentParams, Self::Error> {
|
||||
let document_id =
|
||||
NotEmptyStr::parse(self.document_id).map_err(|_| ErrorCode::DocumentIdIsEmpty)?;
|
||||
Ok(OpenDocumentParams {
|
||||
document_id: document_id.0,
|
||||
})
|
||||
let document_id = Uuid::from_str(&document_id.0).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
|
||||
Ok(OpenDocumentParams { document_id })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ pub struct DocumentRedoUndoPayloadPB {
|
|||
}
|
||||
|
||||
pub struct DocumentRedoUndoParams {
|
||||
pub document_id: String,
|
||||
pub document_id: Uuid,
|
||||
}
|
||||
|
||||
impl TryInto<DocumentRedoUndoParams> for DocumentRedoUndoPayloadPB {
|
||||
|
@ -60,9 +60,8 @@ impl TryInto<DocumentRedoUndoParams> for DocumentRedoUndoPayloadPB {
|
|||
fn try_into(self) -> Result<DocumentRedoUndoParams, Self::Error> {
|
||||
let document_id =
|
||||
NotEmptyStr::parse(self.document_id).map_err(|_| ErrorCode::DocumentIdIsEmpty)?;
|
||||
Ok(DocumentRedoUndoParams {
|
||||
document_id: document_id.0,
|
||||
})
|
||||
let document_id = Uuid::from_str(&document_id.0).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
Ok(DocumentRedoUndoParams { document_id })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +131,7 @@ pub struct CreateDocumentPayloadPB {
|
|||
}
|
||||
|
||||
pub struct CreateDocumentParams {
|
||||
pub document_id: String,
|
||||
pub document_id: Uuid,
|
||||
pub initial_data: Option<DocumentData>,
|
||||
}
|
||||
|
||||
|
@ -141,9 +140,10 @@ impl TryInto<CreateDocumentParams> for CreateDocumentPayloadPB {
|
|||
fn try_into(self) -> Result<CreateDocumentParams, Self::Error> {
|
||||
let document_id =
|
||||
NotEmptyStr::parse(self.document_id).map_err(|_| ErrorCode::DocumentIdIsEmpty)?;
|
||||
let document_id = Uuid::from_str(&document_id.0).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
let initial_data = self.initial_data.map(|data| data.into());
|
||||
Ok(CreateDocumentParams {
|
||||
document_id: document_id.0,
|
||||
document_id,
|
||||
initial_data,
|
||||
})
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ pub struct CloseDocumentPayloadPB {
|
|||
}
|
||||
|
||||
pub struct CloseDocumentParams {
|
||||
pub document_id: String,
|
||||
pub document_id: Uuid,
|
||||
}
|
||||
|
||||
impl TryInto<CloseDocumentParams> for CloseDocumentPayloadPB {
|
||||
|
@ -164,9 +164,8 @@ impl TryInto<CloseDocumentParams> for CloseDocumentPayloadPB {
|
|||
fn try_into(self) -> Result<CloseDocumentParams, Self::Error> {
|
||||
let document_id =
|
||||
NotEmptyStr::parse(self.document_id).map_err(|_| ErrorCode::DocumentIdIsEmpty)?;
|
||||
Ok(CloseDocumentParams {
|
||||
document_id: document_id.0,
|
||||
})
|
||||
let document_id = Uuid::from_str(&document_id.0).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
Ok(CloseDocumentParams { document_id })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +179,7 @@ pub struct ApplyActionPayloadPB {
|
|||
}
|
||||
|
||||
pub struct ApplyActionParams {
|
||||
pub document_id: String,
|
||||
pub document_id: Uuid,
|
||||
pub actions: Vec<BlockAction>,
|
||||
}
|
||||
|
||||
|
@ -189,10 +188,11 @@ impl TryInto<ApplyActionParams> for ApplyActionPayloadPB {
|
|||
fn try_into(self) -> Result<ApplyActionParams, Self::Error> {
|
||||
let document_id =
|
||||
NotEmptyStr::parse(self.document_id).map_err(|_| ErrorCode::DocumentIdIsEmpty)?;
|
||||
let document_id = Uuid::from_str(&document_id.0).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
let actions = NotEmptyVec::parse(self.actions).map_err(|_| ErrorCode::ApplyActionsIsEmpty)?;
|
||||
let actions = actions.0.into_iter().map(BlockAction::from).collect();
|
||||
Ok(ApplyActionParams {
|
||||
document_id: document_id.0,
|
||||
document_id,
|
||||
actions,
|
||||
})
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ pub struct TextDeltaPayloadPB {
|
|||
}
|
||||
|
||||
pub struct TextDeltaParams {
|
||||
pub document_id: String,
|
||||
pub document_id: Uuid,
|
||||
pub text_id: String,
|
||||
pub delta: String,
|
||||
}
|
||||
|
@ -535,10 +535,11 @@ impl TryInto<TextDeltaParams> for TextDeltaPayloadPB {
|
|||
fn try_into(self) -> Result<TextDeltaParams, Self::Error> {
|
||||
let document_id =
|
||||
NotEmptyStr::parse(self.document_id).map_err(|_| ErrorCode::DocumentIdIsEmpty)?;
|
||||
let document_id = Uuid::from_str(&document_id.0).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
let text_id = NotEmptyStr::parse(self.text_id).map_err(|_| ErrorCode::TextIdIsEmpty)?;
|
||||
let delta = self.delta.map_or_else(|| "".to_string(), |delta| delta);
|
||||
Ok(TextDeltaParams {
|
||||
document_id: document_id.0,
|
||||
document_id,
|
||||
text_id: text_id.0,
|
||||
delta,
|
||||
})
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* as well as performing actions on documents. These functions make use of a DocumentManager,
|
||||
* which you can think of as a higher-level interface to interact with documents.
|
||||
*/
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use collab_document::blocks::{
|
||||
|
@ -23,7 +23,7 @@ use flowy_error::{FlowyError, FlowyResult};
|
|||
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
|
||||
use lib_infra::sync_trace;
|
||||
use tracing::instrument;
|
||||
|
||||
use uuid::Uuid;
|
||||
fn upgrade_document(
|
||||
document_manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> FlowyResult<Arc<DocumentManager>> {
|
||||
|
@ -496,7 +496,7 @@ pub(crate) async fn set_awareness_local_state_handler(
|
|||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let data = data.into_inner();
|
||||
let doc_id = data.document_id.clone();
|
||||
let doc_id = Uuid::from_str(&data.document_id)?;
|
||||
manager
|
||||
.set_document_awareness_local_state(&doc_id, data)
|
||||
.await?;
|
||||
|
|
|
@ -14,21 +14,21 @@ use collab_document::document_awareness::DocumentAwarenessUser;
|
|||
use collab_document::document_data::default_document_data;
|
||||
use collab_entity::CollabType;
|
||||
|
||||
use collab_plugins::CollabKVDB;
|
||||
use dashmap::DashMap;
|
||||
use lib_infra::util::timestamp;
|
||||
use tracing::{event, instrument};
|
||||
use tracing::{info, trace};
|
||||
|
||||
use crate::document::{
|
||||
subscribe_document_changed, subscribe_document_snapshot_state, subscribe_document_sync_state,
|
||||
};
|
||||
use collab_integrate::collab_builder::{
|
||||
AppFlowyCollabBuilder, CollabBuilderConfig, CollabPersistenceImpl,
|
||||
};
|
||||
use collab_plugins::CollabKVDB;
|
||||
use dashmap::DashMap;
|
||||
use flowy_document_pub::cloud::DocumentCloudService;
|
||||
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_storage_pub::storage::{CreatedUpload, StorageService};
|
||||
use lib_infra::util::timestamp;
|
||||
use tracing::{event, instrument};
|
||||
use tracing::{info, trace};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::entities::UpdateDocumentAwarenessStatePB;
|
||||
use crate::entities::{
|
||||
|
@ -39,7 +39,7 @@ use crate::reminder::DocumentReminderAction;
|
|||
pub trait DocumentUserService: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn device_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError>;
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,8 @@ pub trait DocumentSnapshotService: Send + Sync {
|
|||
pub struct DocumentManager {
|
||||
pub user_service: Arc<dyn DocumentUserService>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
documents: Arc<DashMap<String, Arc<RwLock<Document>>>>,
|
||||
removing_documents: Arc<DashMap<String, Arc<RwLock<Document>>>>,
|
||||
documents: Arc<DashMap<Uuid, Arc<RwLock<Document>>>>,
|
||||
removing_documents: Arc<DashMap<Uuid, Arc<RwLock<Document>>>>,
|
||||
cloud_service: Arc<dyn DocumentCloudService>,
|
||||
storage_service: Weak<dyn StorageService>,
|
||||
snapshot_service: Arc<dyn DocumentSnapshotService>,
|
||||
|
@ -81,7 +81,7 @@ impl DocumentManager {
|
|||
}
|
||||
|
||||
/// Get the encoded collab of the document.
|
||||
pub async fn get_encoded_collab_with_view_id(&self, doc_id: &str) -> FlowyResult<EncodedCollab> {
|
||||
pub async fn get_encoded_collab_with_view_id(&self, doc_id: &Uuid) -> FlowyResult<EncodedCollab> {
|
||||
let uid = self.user_service.user_id()?;
|
||||
let workspace_id = self.user_service.workspace_id()?;
|
||||
let doc_state =
|
||||
|
@ -139,7 +139,7 @@ impl DocumentManager {
|
|||
pub async fn create_document(
|
||||
&self,
|
||||
_uid: i64,
|
||||
doc_id: &str,
|
||||
doc_id: &Uuid,
|
||||
data: Option<DocumentData>,
|
||||
) -> FlowyResult<EncodedCollab> {
|
||||
if self.is_doc_exist(doc_id).await.unwrap_or(false) {
|
||||
|
@ -151,17 +151,17 @@ impl DocumentManager {
|
|||
let encoded_collab = doc_state_from_document_data(doc_id, data).await?;
|
||||
self
|
||||
.persistence()?
|
||||
.save_collab_to_disk(doc_id, encoded_collab.clone())
|
||||
.save_collab_to_disk(doc_id.to_string().as_str(), encoded_collab.clone())
|
||||
.map_err(internal_error)?;
|
||||
|
||||
// Send the collab data to server with a background task.
|
||||
let cloud_service = self.cloud_service.clone();
|
||||
let cloned_encoded_collab = encoded_collab.clone();
|
||||
let document_id = doc_id.to_string();
|
||||
let workspace_id = self.user_service.workspace_id()?;
|
||||
let doc_id = doc_id.clone();
|
||||
tokio::spawn(async move {
|
||||
let _ = cloud_service
|
||||
.create_document_collab(&workspace_id, &document_id, cloned_encoded_collab)
|
||||
.create_document_collab(&workspace_id, &doc_id, cloned_encoded_collab)
|
||||
.await;
|
||||
});
|
||||
Ok(encoded_collab)
|
||||
|
@ -171,7 +171,7 @@ impl DocumentManager {
|
|||
async fn collab_for_document(
|
||||
&self,
|
||||
uid: i64,
|
||||
doc_id: &str,
|
||||
doc_id: &Uuid,
|
||||
data_source: DataSource,
|
||||
sync_enable: bool,
|
||||
) -> FlowyResult<Arc<RwLock<Document>>> {
|
||||
|
@ -195,7 +195,7 @@ impl DocumentManager {
|
|||
}
|
||||
|
||||
/// Return a document instance if the document is already opened.
|
||||
pub async fn editable_document(&self, doc_id: &str) -> FlowyResult<Arc<RwLock<Document>>> {
|
||||
pub async fn editable_document(&self, doc_id: &Uuid) -> FlowyResult<Arc<RwLock<Document>>> {
|
||||
if let Some(doc) = self.documents.get(doc_id).map(|item| item.value().clone()) {
|
||||
return Ok(doc);
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ impl DocumentManager {
|
|||
#[tracing::instrument(level = "info", skip(self), err)]
|
||||
async fn create_document_instance(
|
||||
&self,
|
||||
doc_id: &str,
|
||||
doc_id: &Uuid,
|
||||
enable_sync: bool,
|
||||
) -> FlowyResult<Arc<RwLock<Document>>> {
|
||||
let uid = self.user_service.user_id()?;
|
||||
|
@ -260,7 +260,7 @@ impl DocumentManager {
|
|||
subscribe_document_snapshot_state(&lock);
|
||||
subscribe_document_sync_state(&lock);
|
||||
}
|
||||
self.documents.insert(doc_id.to_string(), document.clone());
|
||||
self.documents.insert(doc_id.clone(), document.clone());
|
||||
}
|
||||
Ok(document)
|
||||
},
|
||||
|
@ -273,21 +273,21 @@ impl DocumentManager {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn get_document_data(&self, doc_id: &str) -> FlowyResult<DocumentData> {
|
||||
pub async fn get_document_data(&self, doc_id: &Uuid) -> FlowyResult<DocumentData> {
|
||||
let document = self.get_document(doc_id).await?;
|
||||
let document = document.read().await;
|
||||
document.get_document_data().map_err(internal_error)
|
||||
}
|
||||
pub async fn get_document_text(&self, doc_id: &str) -> FlowyResult<String> {
|
||||
pub async fn get_document_text(&self, doc_id: &Uuid) -> FlowyResult<String> {
|
||||
let document = self.get_document(doc_id).await?;
|
||||
let document = document.read().await;
|
||||
let text = document.to_plain_text(true, false)?;
|
||||
let text = document.paragraphs().join("\n");
|
||||
Ok(text)
|
||||
}
|
||||
|
||||
/// Return a document instance.
|
||||
/// The returned document might or might not be able to sync with the cloud.
|
||||
async fn get_document(&self, doc_id: &str) -> FlowyResult<Arc<RwLock<Document>>> {
|
||||
async fn get_document(&self, doc_id: &Uuid) -> FlowyResult<Arc<RwLock<Document>>> {
|
||||
if let Some(doc) = self.documents.get(doc_id).map(|item| item.value().clone()) {
|
||||
return Ok(doc);
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ impl DocumentManager {
|
|||
Ok(document)
|
||||
}
|
||||
|
||||
pub async fn open_document(&self, doc_id: &str) -> FlowyResult<()> {
|
||||
pub async fn open_document(&self, doc_id: &Uuid) -> FlowyResult<()> {
|
||||
if let Some(mutex_document) = self.restore_document_from_removing(doc_id) {
|
||||
let lock = mutex_document.read().await;
|
||||
lock.start_init_sync();
|
||||
|
@ -314,7 +314,7 @@ impl DocumentManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn close_document(&self, doc_id: &str) -> FlowyResult<()> {
|
||||
pub async fn close_document(&self, doc_id: &Uuid) -> FlowyResult<()> {
|
||||
if let Some((doc_id, document)) = self.documents.remove(doc_id) {
|
||||
{
|
||||
// clear the awareness state when close the document
|
||||
|
@ -340,11 +340,12 @@ impl DocumentManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_document(&self, doc_id: &str) -> FlowyResult<()> {
|
||||
pub async fn delete_document(&self, doc_id: &Uuid) -> FlowyResult<()> {
|
||||
let uid = self.user_service.user_id()?;
|
||||
let workspace_id = self.user_service.workspace_id()?;
|
||||
if let Some(db) = self.user_service.collab_db(uid)?.upgrade() {
|
||||
db.delete_doc(uid, &workspace_id, doc_id).await?;
|
||||
db.delete_doc(uid, &workspace_id.to_string(), &doc_id.to_string())
|
||||
.await?;
|
||||
// When deleting a document, we need to remove it from the cache.
|
||||
self.documents.remove(doc_id);
|
||||
}
|
||||
|
@ -354,7 +355,7 @@ impl DocumentManager {
|
|||
#[instrument(level = "debug", skip_all, err)]
|
||||
pub async fn set_document_awareness_local_state(
|
||||
&self,
|
||||
doc_id: &str,
|
||||
doc_id: &Uuid,
|
||||
state: UpdateDocumentAwarenessStatePB,
|
||||
) -> FlowyResult<bool> {
|
||||
let uid = self.user_service.user_id()?;
|
||||
|
@ -379,12 +380,12 @@ impl DocumentManager {
|
|||
/// Return the list of snapshots of the document.
|
||||
pub async fn get_document_snapshot_meta(
|
||||
&self,
|
||||
document_id: &str,
|
||||
document_id: &Uuid,
|
||||
_limit: usize,
|
||||
) -> FlowyResult<Vec<DocumentSnapshotMetaPB>> {
|
||||
let metas = self
|
||||
.snapshot_service
|
||||
.get_document_snapshot_metas(document_id)?
|
||||
.get_document_snapshot_metas(document_id.to_string().as_str())?
|
||||
.into_iter()
|
||||
.map(|meta| DocumentSnapshotMetaPB {
|
||||
snapshot_id: meta.snapshot_id,
|
||||
|
@ -434,11 +435,13 @@ impl DocumentManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn is_doc_exist(&self, doc_id: &str) -> FlowyResult<bool> {
|
||||
async fn is_doc_exist(&self, doc_id: &Uuid) -> FlowyResult<bool> {
|
||||
let uid = self.user_service.user_id()?;
|
||||
let workspace_id = self.user_service.workspace_id()?;
|
||||
if let Some(collab_db) = self.user_service.collab_db(uid)?.upgrade() {
|
||||
let is_exist = collab_db.is_exist(uid, &workspace_id, doc_id).await?;
|
||||
let is_exist = collab_db
|
||||
.is_exist(uid, &workspace_id.to_string(), &doc_id.to_string())
|
||||
.await?;
|
||||
Ok(is_exist)
|
||||
} else {
|
||||
Ok(false)
|
||||
|
@ -463,7 +466,7 @@ impl DocumentManager {
|
|||
&self.storage_service
|
||||
}
|
||||
|
||||
fn restore_document_from_removing(&self, doc_id: &str) -> Option<Arc<RwLock<Document>>> {
|
||||
fn restore_document_from_removing(&self, doc_id: &Uuid) -> Option<Arc<RwLock<Document>>> {
|
||||
let (doc_id, doc) = self.removing_documents.remove(doc_id)?;
|
||||
trace!(
|
||||
"move document {} from removing_documents to documents",
|
||||
|
@ -475,7 +478,7 @@ impl DocumentManager {
|
|||
}
|
||||
|
||||
async fn doc_state_from_document_data(
|
||||
doc_id: &str,
|
||||
doc_id: &Uuid,
|
||||
data: Option<DocumentData>,
|
||||
) -> Result<EncodedCollab, FlowyError> {
|
||||
let doc_id = doc_id.to_string();
|
||||
|
|
|
@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Default, ProtoBuf)]
|
||||
|
@ -96,7 +97,7 @@ pub struct ParseType {
|
|||
}
|
||||
|
||||
pub struct ConvertDocumentParams {
|
||||
pub document_id: String,
|
||||
pub document_id: Uuid,
|
||||
pub range: Option<Range>,
|
||||
pub parse_types: ParseType,
|
||||
}
|
||||
|
@ -140,10 +141,11 @@ impl TryInto<ConvertDocumentParams> for ConvertDocumentPayloadPB {
|
|||
fn try_into(self) -> Result<ConvertDocumentParams, Self::Error> {
|
||||
let document_id =
|
||||
NotEmptyStr::parse(self.document_id).map_err(|_| ErrorCode::DocumentIdIsEmpty)?;
|
||||
let document_id = Uuid::parse_str(&document_id.0).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
let range = self.range.map(|data| data.into());
|
||||
|
||||
Ok(ConvertDocumentParams {
|
||||
document_id: document_id.0,
|
||||
document_id,
|
||||
range,
|
||||
parse_types: self.parse_types.into(),
|
||||
})
|
||||
|
|
|
@ -9,8 +9,8 @@ use crate::document::util::{gen_document_id, gen_id, DocumentTest};
|
|||
async fn undo_redo_test() {
|
||||
let test = DocumentTest::new();
|
||||
|
||||
let doc_id: String = gen_document_id();
|
||||
let data = default_document_data(&doc_id);
|
||||
let doc_id = gen_document_id();
|
||||
let data = default_document_data(&doc_id.to_string());
|
||||
|
||||
// create a document
|
||||
_ = test
|
||||
|
|
|
@ -11,8 +11,8 @@ async fn restore_document() {
|
|||
let test = DocumentTest::new();
|
||||
|
||||
// create a document
|
||||
let doc_id: String = gen_document_id();
|
||||
let data = default_document_data(&doc_id);
|
||||
let doc_id = gen_document_id();
|
||||
let data = default_document_data(&doc_id.to_string());
|
||||
let uid = test.user_service.user_id().unwrap();
|
||||
test
|
||||
.create_document(uid, &doc_id, Some(data.clone()))
|
||||
|
@ -55,8 +55,8 @@ async fn restore_document() {
|
|||
async fn document_apply_insert_action() {
|
||||
let test = DocumentTest::new();
|
||||
let uid = test.user_service.user_id().unwrap();
|
||||
let doc_id: String = gen_document_id();
|
||||
let data = default_document_data(&doc_id);
|
||||
let doc_id = gen_document_id();
|
||||
let data = default_document_data(&doc_id.to_string());
|
||||
|
||||
// create a document
|
||||
_ = test.create_document(uid, &doc_id, Some(data.clone())).await;
|
||||
|
@ -111,9 +111,9 @@ async fn document_apply_insert_action() {
|
|||
#[tokio::test]
|
||||
async fn document_apply_update_page_action() {
|
||||
let test = DocumentTest::new();
|
||||
let doc_id: String = gen_document_id();
|
||||
let doc_id = gen_document_id();
|
||||
let uid = test.user_service.user_id().unwrap();
|
||||
let data = default_document_data(&doc_id);
|
||||
let data = default_document_data(&doc_id.to_string());
|
||||
|
||||
// create a document
|
||||
_ = test.create_document(uid, &doc_id, Some(data.clone())).await;
|
||||
|
@ -158,8 +158,8 @@ async fn document_apply_update_page_action() {
|
|||
async fn document_apply_update_action() {
|
||||
let test = DocumentTest::new();
|
||||
let uid = test.user_service.user_id().unwrap();
|
||||
let doc_id: String = gen_document_id();
|
||||
let data = default_document_data(&doc_id);
|
||||
let doc_id = gen_document_id();
|
||||
let data = default_document_data(&doc_id.to_string());
|
||||
|
||||
// create a document
|
||||
_ = test.create_document(uid, &doc_id, Some(data.clone())).await;
|
||||
|
|
|
@ -7,11 +7,6 @@ use collab::preclude::CollabPlugin;
|
|||
use collab_document::blocks::DocumentData;
|
||||
use collab_document::document::Document;
|
||||
use collab_document::document_data::default_document_data;
|
||||
use nanoid::nanoid;
|
||||
use tempfile::TempDir;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing_subscriber::{fmt::Subscriber, util::SubscriberInitExt, EnvFilter};
|
||||
|
||||
use collab_integrate::collab_builder::{
|
||||
AppFlowyCollabBuilder, CollabCloudPluginProvider, CollabPluginProviderContext,
|
||||
CollabPluginProviderType, WorkspaceCollabIntegrate,
|
||||
|
@ -24,6 +19,11 @@ use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
|||
use flowy_storage_pub::storage::{CreatedUpload, FileProgressReceiver, StorageService};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use lib_infra::box_any::BoxAny;
|
||||
use nanoid::nanoid;
|
||||
use tempfile::TempDir;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing_subscriber::{fmt::Subscriber, util::SubscriberInitExt, EnvFilter};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct DocumentTest {
|
||||
inner: DocumentManager,
|
||||
|
@ -63,7 +63,7 @@ impl Deref for DocumentTest {
|
|||
}
|
||||
|
||||
pub struct FakeUser {
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
collab_db: Arc<CollabKVDB>,
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ impl FakeUser {
|
|||
let tempdir = TempDir::new().unwrap();
|
||||
let path = tempdir.into_path();
|
||||
let collab_db = Arc::new(CollabKVDB::open(path).unwrap());
|
||||
let workspace_id = uuid::Uuid::new_v4().to_string();
|
||||
let workspace_id = uuid::Uuid::new_v4();
|
||||
|
||||
Self {
|
||||
collab_db,
|
||||
|
@ -88,7 +88,7 @@ impl DocumentUserService for FakeUser {
|
|||
Ok(1)
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError> {
|
||||
Ok(self.workspace_id.clone())
|
||||
}
|
||||
|
||||
|
@ -115,8 +115,8 @@ pub fn setup_log() {
|
|||
|
||||
pub async fn create_and_open_empty_document() -> (DocumentTest, Arc<RwLock<Document>>, String) {
|
||||
let test = DocumentTest::new();
|
||||
let doc_id: String = gen_document_id();
|
||||
let data = default_document_data(&doc_id);
|
||||
let doc_id = gen_document_id();
|
||||
let data = default_document_data(&doc_id.to_string());
|
||||
let uid = test.user_service.user_id().unwrap();
|
||||
// create a document
|
||||
test
|
||||
|
@ -130,9 +130,8 @@ pub async fn create_and_open_empty_document() -> (DocumentTest, Arc<RwLock<Docum
|
|||
(test, document, data.page_id)
|
||||
}
|
||||
|
||||
pub fn gen_document_id() -> String {
|
||||
let uuid = uuid::Uuid::new_v4();
|
||||
uuid.to_string()
|
||||
pub fn gen_document_id() -> Uuid {
|
||||
uuid::Uuid::new_v4()
|
||||
}
|
||||
|
||||
pub fn gen_id() -> String {
|
||||
|
@ -145,8 +144,8 @@ pub struct LocalTestDocumentCloudServiceImpl();
|
|||
impl DocumentCloudService for LocalTestDocumentCloudServiceImpl {
|
||||
async fn get_document_doc_state(
|
||||
&self,
|
||||
document_id: &str,
|
||||
_workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let document_id = document_id.to_string();
|
||||
Err(FlowyError::new(
|
||||
|
@ -157,26 +156,26 @@ impl DocumentCloudService for LocalTestDocumentCloudServiceImpl {
|
|||
|
||||
async fn get_document_snapshots(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
_limit: usize,
|
||||
_workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
limit: usize,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<DocumentSnapshot>, FlowyError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
async fn get_document_data(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
_workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<DocumentData>, FlowyError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn create_document_collab(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_document_id: &str,
|
||||
_encoded_collab: EncodedCollab,
|
||||
workspace_id: &Uuid,
|
||||
document_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -257,14 +256,14 @@ impl DocumentSnapshotService for DocumentTestSnapshot {
|
|||
}
|
||||
|
||||
struct WorkspaceCollabIntegrateImpl {
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
}
|
||||
impl WorkspaceCollabIntegrate for WorkspaceCollabIntegrateImpl {
|
||||
fn workspace_id(&self) -> Result<String, Error> {
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError> {
|
||||
Ok(self.workspace_id.clone())
|
||||
}
|
||||
|
||||
fn device_id(&self) -> Result<String, Error> {
|
||||
fn device_id(&self) -> Result<String, FlowyError> {
|
||||
Ok("fake_device_id".to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ collab-plugins = { workspace = true, optional = true }
|
|||
collab-folder = { workspace = true, optional = true }
|
||||
client-api = { workspace = true, optional = true }
|
||||
tantivy = { version = "0.22.0", optional = true }
|
||||
uuid.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["impl_from_dispatch_error", "impl_from_serde", "impl_from_reqwest", "impl_from_sqlite"]
|
||||
|
|
|
@ -256,3 +256,9 @@ impl From<collab::error::CollabError> for FlowyError {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<uuid::Error> for FlowyError {
|
||||
fn from(value: uuid::Error) -> Self {
|
||||
FlowyError::internal().with_context(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ pub trait FolderCloudService: Send + Sync + 'static {
|
|||
/// Returns error if the cloud service doesn't support multiple workspaces
|
||||
async fn create_workspace(&self, uid: i64, name: &str) -> Result<Workspace, FlowyError>;
|
||||
|
||||
async fn open_workspace(&self, workspace_id: &str) -> Result<(), FlowyError>;
|
||||
async fn open_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError>;
|
||||
|
||||
/// Returns all workspaces of the user.
|
||||
/// Returns vec![] if the cloud service doesn't support multiple workspaces
|
||||
|
@ -23,7 +23,7 @@ pub trait FolderCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn get_folder_data(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: &i64,
|
||||
) -> Result<Option<FolderData>, FlowyError>;
|
||||
|
||||
|
@ -35,21 +35,21 @@ pub trait FolderCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn get_folder_doc_state(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
collab_type: CollabType,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError>;
|
||||
|
||||
async fn full_sync_collab_object(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
params: FullSyncCollabParams,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn batch_create_folder_collab_objects(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
objects: Vec<FolderCollabParams>,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
|
@ -57,64 +57,64 @@ pub trait FolderCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn publish_view(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
payload: Vec<PublishPayload>,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn unpublish_views(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
view_ids: Vec<String>,
|
||||
workspace_id: &Uuid,
|
||||
view_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn get_publish_info(&self, view_id: &str) -> Result<PublishInfo, FlowyError>;
|
||||
async fn get_publish_info(&self, view_id: &Uuid) -> Result<PublishInfo, FlowyError>;
|
||||
|
||||
async fn set_publish_name(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
view_id: String,
|
||||
workspace_id: &Uuid,
|
||||
view_id: Uuid,
|
||||
new_name: String,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn set_publish_namespace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
new_namespace: String,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn list_published_views(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<PublishInfoView>, FlowyError>;
|
||||
|
||||
async fn get_default_published_view_info(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<PublishInfo, FlowyError>;
|
||||
|
||||
async fn set_default_published_view(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
view_id: uuid::Uuid,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn remove_default_published_view(&self, workspace_id: &str) -> Result<(), FlowyError>;
|
||||
async fn remove_default_published_view(&self, workspace_id: &Uuid) -> Result<(), FlowyError>;
|
||||
|
||||
async fn get_publish_namespace(&self, workspace_id: &str) -> Result<String, FlowyError>;
|
||||
async fn get_publish_namespace(&self, workspace_id: &Uuid) -> Result<String, FlowyError>;
|
||||
|
||||
async fn import_zip(&self, file_path: &str) -> Result<(), FlowyError>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FolderCollabParams {
|
||||
pub object_id: String,
|
||||
pub object_id: Uuid,
|
||||
pub encoded_collab_v1: Vec<u8>,
|
||||
pub collab_type: CollabType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FullSyncCollabParams {
|
||||
pub object_id: String,
|
||||
pub object_id: Uuid,
|
||||
pub encoded_collab: EncodedCollab,
|
||||
pub collab_type: CollabType,
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use collab_entity::CollabType;
|
|||
use collab_folder::ViewLayout;
|
||||
use flowy_error::FlowyResult;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct QueryCollab {
|
||||
pub collab_type: CollabType,
|
||||
|
@ -17,14 +18,14 @@ pub trait FolderQueryService: Send + Sync + 'static {
|
|||
/// the provided view layout, given that the parent view is not a space
|
||||
async fn get_surrounding_view_ids_with_view_layout(
|
||||
&self,
|
||||
parent_view_id: &str,
|
||||
parent_view_id: &Uuid,
|
||||
view_layout: ViewLayout,
|
||||
) -> Vec<String>;
|
||||
) -> Vec<Uuid>;
|
||||
|
||||
async fn get_collab(&self, object_id: &str, collab_type: CollabType) -> Option<QueryCollab>;
|
||||
async fn get_collab(&self, object_id: &Uuid, collab_type: CollabType) -> Option<QueryCollab>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait FolderViewEdit: Send + Sync + 'static {
|
||||
async fn set_view_title_if_empty(&self, view_id: &str, title: &str) -> FlowyResult<()>;
|
||||
async fn set_view_title_if_empty(&self, view_id: &Uuid, title: &str) -> FlowyResult<()>;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ use crate::share::{ImportData, ImportItem, ImportParams, ImportType};
|
|||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::validator_fn::required_not_empty_str;
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Clone, Debug, ProtoBuf_Enum)]
|
||||
|
@ -76,6 +78,8 @@ impl TryInto<ImportParams> for ImportPayloadPB {
|
|||
.map_err(|_| FlowyError::invalid_view_id())?
|
||||
.0;
|
||||
|
||||
let parent_view_id = Uuid::from_str(&parent_view_id)?;
|
||||
|
||||
let items = self
|
||||
.items
|
||||
.into_iter()
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use collab_folder::{View, ViewIcon, ViewLayout};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_folder_pub::cloud::gen_view_id;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::entities::icon::ViewIconPB;
|
||||
use crate::entities::parser::view::{ViewIdentify, ViewName, ViewThumbnail};
|
||||
|
@ -322,10 +323,10 @@ pub struct CreateOrphanViewPayloadPB {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CreateViewParams {
|
||||
pub parent_view_id: String,
|
||||
pub parent_view_id: Uuid,
|
||||
pub name: String,
|
||||
pub layout: ViewLayoutPB,
|
||||
pub view_id: String,
|
||||
pub view_id: Uuid,
|
||||
pub initial_data: ViewData,
|
||||
pub meta: HashMap<String, String>,
|
||||
// Mark the view as current view after creation.
|
||||
|
@ -346,9 +347,13 @@ impl TryInto<CreateViewParams> for CreateViewPayloadPB {
|
|||
|
||||
fn try_into(self) -> Result<CreateViewParams, Self::Error> {
|
||||
let name = ViewName::parse(self.name)?.0;
|
||||
let parent_view_id = ViewIdentify::parse(self.parent_view_id)?.0;
|
||||
let parent_view_id = ViewIdentify::parse(self.parent_view_id)
|
||||
.and_then(|id| Uuid::from_str(&id.0).map_err(|err| ErrorCode::InvalidParams))?;
|
||||
// if view_id is not provided, generate a new view_id
|
||||
let view_id = self.view_id.unwrap_or_else(|| gen_view_id().to_string());
|
||||
let view_id = self
|
||||
.view_id
|
||||
.and_then(|v| Uuid::parse_str(&v).ok())
|
||||
.unwrap_or_else(|| gen_view_id());
|
||||
|
||||
Ok(CreateViewParams {
|
||||
parent_view_id,
|
||||
|
@ -371,13 +376,13 @@ impl TryInto<CreateViewParams> for CreateOrphanViewPayloadPB {
|
|||
|
||||
fn try_into(self) -> Result<CreateViewParams, Self::Error> {
|
||||
let name = ViewName::parse(self.name)?.0;
|
||||
let parent_view_id = ViewIdentify::parse(self.view_id.clone())?.0;
|
||||
let view_id = Uuid::parse_str(&self.view_id).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
|
||||
Ok(CreateViewParams {
|
||||
parent_view_id,
|
||||
parent_view_id: view_id.clone(),
|
||||
name,
|
||||
layout: self.layout,
|
||||
view_id: self.view_id,
|
||||
view_id,
|
||||
initial_data: ViewData::Data(self.initial_data.into()),
|
||||
meta: Default::default(),
|
||||
set_as_current: false,
|
||||
|
@ -564,9 +569,9 @@ impl TryInto<MoveViewParams> for MoveViewPayloadPB {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct MoveNestedViewParams {
|
||||
pub view_id: String,
|
||||
pub new_parent_id: String,
|
||||
pub prev_view_id: Option<String>,
|
||||
pub view_id: Uuid,
|
||||
pub new_parent_id: Uuid,
|
||||
pub prev_view_id: Option<Uuid>,
|
||||
pub from_section: Option<ViewSectionPB>,
|
||||
pub to_section: Option<ViewSectionPB>,
|
||||
}
|
||||
|
@ -575,9 +580,20 @@ impl TryInto<MoveNestedViewParams> for MoveNestedViewPayloadPB {
|
|||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<MoveNestedViewParams, Self::Error> {
|
||||
let view_id = ViewIdentify::parse(self.view_id)?.0;
|
||||
let view_id = Uuid::from_str(&ViewIdentify::parse(self.view_id)?.0)
|
||||
.map_err(|_| ErrorCode::InvalidParams)?;
|
||||
|
||||
let new_parent_id = ViewIdentify::parse(self.new_parent_id)?.0;
|
||||
let prev_view_id = self.prev_view_id;
|
||||
let new_parent_id = Uuid::from_str(&new_parent_id).map_err(|_| ErrorCode::InvalidParams)?;
|
||||
|
||||
let prev_view_id = match self.prev_view_id {
|
||||
Some(prev_view_id) => Some(
|
||||
Uuid::from_str(&ViewIdentify::parse(prev_view_id)?.0)
|
||||
.map_err(|_| ErrorCode::InvalidParams)?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok(MoveNestedViewParams {
|
||||
view_id,
|
||||
new_parent_id,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use std::sync::{Arc, Weak};
|
||||
use tracing::instrument;
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::instrument;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::manager::FolderManager;
|
||||
|
@ -443,7 +444,12 @@ pub(crate) async fn unpublish_views_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params = data.into_inner();
|
||||
folder.unpublish_views(params.view_ids).await?;
|
||||
let view_ids = params
|
||||
.view_ids
|
||||
.into_iter()
|
||||
.flat_map(|id| Uuid::from_str(&id).ok())
|
||||
.collect::<Vec<_>>();
|
||||
folder.unpublish_views(view_ids).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -454,6 +460,7 @@ pub(crate) async fn get_publish_info_handler(
|
|||
) -> DataResult<PublishInfoResponsePB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let view_id = data.into_inner().value;
|
||||
let view_id = Uuid::from_str(&view_id)?;
|
||||
let info = folder.get_publish_info(&view_id).await?;
|
||||
data_result_ok(PublishInfoResponsePB::from(info))
|
||||
}
|
||||
|
@ -465,6 +472,7 @@ pub(crate) async fn set_publish_name_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let SetPublishNamePB { view_id, new_name } = data.into_inner();
|
||||
let view_id = Uuid::from_str(&view_id)?;
|
||||
folder.set_publish_name(view_id, new_name).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -44,16 +44,18 @@ use flowy_sqlite::kv::KVStorePreferences;
|
|||
use futures::future;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::RwLockWriteGuard;
|
||||
use tracing::{error, info, instrument};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub trait FolderUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError>;
|
||||
|
||||
fn is_folder_exist_on_disk(&self, uid: i64, workspace_id: &str) -> FlowyResult<bool>;
|
||||
fn is_folder_exist_on_disk(&self, uid: i64, workspace_id: &Uuid) -> FlowyResult<bool>;
|
||||
}
|
||||
|
||||
pub struct FolderManager {
|
||||
|
@ -111,7 +113,7 @@ impl FolderManager {
|
|||
Ok::<WorkspacePB, FlowyError>(workspace)
|
||||
};
|
||||
|
||||
match folder.get_workspace_info(&workspace_id) {
|
||||
match folder.get_workspace_info(&workspace_id.to_string()) {
|
||||
None => Err(FlowyError::record_not_found().with_context("Can not find the workspace")),
|
||||
Some(workspace) => workspace_pb_from_workspace(workspace, &folder),
|
||||
}
|
||||
|
@ -127,14 +129,14 @@ impl FolderManager {
|
|||
.ok_or_else(|| internal_error("The folder is not initialized"))?
|
||||
.read()
|
||||
.await
|
||||
.get_folder_data(&workspace_id)
|
||||
.get_folder_data(&workspace_id.to_string())
|
||||
.ok_or_else(|| internal_error("Workspace id not match the id in current folder"))?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub async fn gather_publish_encode_collab(
|
||||
&self,
|
||||
view_id: &str,
|
||||
view_id: &Uuid,
|
||||
layout: &ViewLayout,
|
||||
) -> FlowyResult<GatherEncodedCollab> {
|
||||
let handler = self.get_handler(layout)?;
|
||||
|
@ -177,7 +179,7 @@ impl FolderManager {
|
|||
pub(crate) async fn make_folder<T: Into<Option<FolderNotify>>>(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
collab_db: Weak<CollabKVDB>,
|
||||
data_source: Option<DataSource>,
|
||||
folder_notifier: T,
|
||||
|
@ -187,8 +189,7 @@ impl FolderManager {
|
|||
let config = CollabBuilderConfig::default().sync_enable(true);
|
||||
|
||||
let data_source = data_source.unwrap_or_else(|| {
|
||||
CollabPersistenceImpl::new(collab_db.clone(), uid, workspace_id.to_string())
|
||||
.into_data_source()
|
||||
CollabPersistenceImpl::new(collab_db.clone(), uid, workspace_id.clone()).into_data_source()
|
||||
});
|
||||
|
||||
let object_id = workspace_id;
|
||||
|
@ -218,8 +219,11 @@ impl FolderManager {
|
|||
"Clear the folder data and try to open the folder again due to: {}",
|
||||
err
|
||||
);
|
||||
|
||||
if let Some(db) = self.user.collab_db(uid).ok().and_then(|a| a.upgrade()) {
|
||||
let _ = db.delete_doc(uid, workspace_id, workspace_id).await;
|
||||
let _ = db
|
||||
.delete_doc(uid, &workspace_id.to_string(), &object_id.to_string())
|
||||
.await;
|
||||
}
|
||||
Err(err.into())
|
||||
},
|
||||
|
@ -229,7 +233,7 @@ impl FolderManager {
|
|||
pub(crate) async fn create_folder_with_data(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
collab_db: Weak<CollabKVDB>,
|
||||
notifier: Option<FolderNotify>,
|
||||
folder_data: Option<FolderData>,
|
||||
|
@ -240,8 +244,8 @@ impl FolderManager {
|
|||
.collab_builder
|
||||
.collab_object(workspace_id, uid, object_id, CollabType::Folder)?;
|
||||
|
||||
let doc_state = CollabPersistenceImpl::new(collab_db.clone(), uid, workspace_id.to_string())
|
||||
.into_data_source();
|
||||
let doc_state =
|
||||
CollabPersistenceImpl::new(collab_db.clone(), uid, workspace_id.clone()).into_data_source();
|
||||
let folder = self
|
||||
.collab_builder
|
||||
.create_folder(
|
||||
|
@ -317,7 +321,7 @@ impl FolderManager {
|
|||
_token: &str,
|
||||
is_new: bool,
|
||||
data_source: FolderInitDataSource,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> FlowyResult<()> {
|
||||
// Create the default workspace if the user is new
|
||||
info!("initialize_when_sign_up: is_new: {}", is_new);
|
||||
|
@ -377,7 +381,7 @@ impl FolderManager {
|
|||
let workspace_id = self.user.workspace_id()?;
|
||||
let latest_view = self.get_current_view().await;
|
||||
Ok(WorkspaceSettingPB {
|
||||
workspace_id,
|
||||
workspace_id: workspace_id.to_string(),
|
||||
latest_view,
|
||||
})
|
||||
}
|
||||
|
@ -495,7 +499,7 @@ impl FolderManager {
|
|||
.ok_or_else(|| FlowyError::internal().with_context("folder is not initialized"))?;
|
||||
let folder = lock.read().await;
|
||||
let workspace = folder
|
||||
.get_workspace_info(&workspace_id)
|
||||
.get_workspace_info(&workspace_id.to_string())
|
||||
.ok_or_else(|| FlowyError::record_not_found().with_context("Can not find the workspace"))?;
|
||||
|
||||
let views = folder
|
||||
|
@ -606,8 +610,9 @@ impl FolderManager {
|
|||
// Drop the folder lock explicitly to avoid deadlock when following calls contains 'self'
|
||||
drop(folder);
|
||||
|
||||
let view_id = Uuid::from_str(view_id)?;
|
||||
let handler = self.get_handler(&view.layout)?;
|
||||
handler.close_view(view_id).await?;
|
||||
handler.close_view(&view_id).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -844,24 +849,28 @@ impl FolderManager {
|
|||
let prev_view_id = params.prev_view_id;
|
||||
let from_section = params.from_section;
|
||||
let to_section = params.to_section;
|
||||
let view = self.get_view_pb(&view_id).await?;
|
||||
let view = self.get_view_pb(&view_id.to_string()).await?;
|
||||
// if the view is locked, the view can't be moved
|
||||
if view.is_locked.unwrap_or(false) {
|
||||
return Err(FlowyError::view_is_locked());
|
||||
}
|
||||
|
||||
let old_parent_id = view.parent_view_id;
|
||||
let old_parent_id = Uuid::from_str(&view.parent_view_id)?;
|
||||
if let Some(lock) = self.mutex_folder.load_full() {
|
||||
let mut folder = lock.write().await;
|
||||
folder.move_nested_view(&view_id, &new_parent_id, prev_view_id);
|
||||
folder.move_nested_view(
|
||||
&view_id.to_string(),
|
||||
&new_parent_id.to_string(),
|
||||
prev_view_id.map(|s| s.to_string()),
|
||||
);
|
||||
if from_section != to_section {
|
||||
if to_section == Some(ViewSectionPB::Private) {
|
||||
folder.add_private_view_ids(vec![view_id.clone()]);
|
||||
folder.add_private_view_ids(vec![view_id.to_string()]);
|
||||
} else {
|
||||
folder.delete_private_view_ids(vec![view_id.clone()]);
|
||||
folder.delete_private_view_ids(vec![view_id.to_string()]);
|
||||
}
|
||||
}
|
||||
notify_parent_view_did_change(&workspace_id, &folder, vec![new_parent_id, old_parent_id]);
|
||||
notify_parent_view_did_change(workspace_id, &folder, vec![new_parent_id, old_parent_id]);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -912,7 +921,8 @@ impl FolderManager {
|
|||
if let Some(lock) = self.mutex_folder.load_full() {
|
||||
let mut folder = lock.write().await;
|
||||
folder.move_view(view_id, actual_from_index as u32, actual_to_index as u32);
|
||||
notify_parent_view_did_change(&workspace_id, &folder, vec![parent_view_id]);
|
||||
let parent_view_id = Uuid::from_str(&parent_view_id)?;
|
||||
notify_parent_view_did_change(workspace_id, &folder, vec![parent_view_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1115,7 +1125,8 @@ impl FolderManager {
|
|||
view.name,
|
||||
view.layout
|
||||
);
|
||||
let view_data = handler.duplicate_view(&view.id).await?;
|
||||
let view_id = Uuid::from_str(&view.id)?;
|
||||
let view_data = handler.duplicate_view(&view_id).await?;
|
||||
|
||||
let index = self
|
||||
.get_view_relation(¤t_parent_id)
|
||||
|
@ -1151,12 +1162,13 @@ impl FolderManager {
|
|||
view.name.clone()
|
||||
};
|
||||
|
||||
let parent_view_id = Uuid::from_str(¤t_parent_id)?;
|
||||
let duplicate_params = CreateViewParams {
|
||||
parent_view_id: current_parent_id.clone(),
|
||||
parent_view_id,
|
||||
name,
|
||||
layout: view.layout.clone().into(),
|
||||
initial_data: ViewData::DuplicateData(view_data),
|
||||
view_id: gen_view_id().to_string(),
|
||||
view_id: gen_view_id(),
|
||||
meta: Default::default(),
|
||||
set_as_current: is_source_view && open_after_duplicated,
|
||||
index,
|
||||
|
@ -1176,7 +1188,7 @@ impl FolderManager {
|
|||
|
||||
if sync_after_create {
|
||||
if let Some(encoded_collab) = encoded_collab {
|
||||
let object_id = duplicated_view.id.clone();
|
||||
let object_id = Uuid::from_str(&duplicated_view.id)?;
|
||||
let collab_type = match duplicated_view.layout {
|
||||
ViewLayout::Document => CollabType::Document,
|
||||
ViewLayout::Board | ViewLayout::Grid | ViewLayout::Calendar => CollabType::Database,
|
||||
|
@ -1208,20 +1220,20 @@ impl FolderManager {
|
|||
is_source_view = false
|
||||
}
|
||||
|
||||
let workspace_id = &self.user.workspace_id()?;
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let parent_view_id = Uuid::from_str(&parent_view_id)?;
|
||||
|
||||
// Sync the view to the cloud
|
||||
if sync_after_create {
|
||||
self
|
||||
.cloud_service
|
||||
.batch_create_folder_collab_objects(workspace_id, objects)
|
||||
.batch_create_folder_collab_objects(&workspace_id, objects)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// notify the update here
|
||||
let folder = lock.read().await;
|
||||
notify_parent_view_did_change(workspace_id, &folder, vec![parent_view_id.to_string()]);
|
||||
|
||||
notify_parent_view_did_change(workspace_id, &folder, vec![parent_view_id]);
|
||||
let duplicated_view = self.get_view_pb(&new_view_id).await?;
|
||||
|
||||
Ok(duplicated_view)
|
||||
|
@ -1242,6 +1254,7 @@ impl FolderManager {
|
|||
let view_layout: ViewLayout = view.layout.clone().into();
|
||||
if let Some(handle) = self.operation_handlers.get(&view_layout) {
|
||||
info!("Open view: {}-{}", view.name, view.id);
|
||||
let view_id = Uuid::from_str(&view.id)?;
|
||||
if let Err(err) = handle.open_view(&view_id).await {
|
||||
error!("Open view error: {:?}", err);
|
||||
}
|
||||
|
@ -1250,7 +1263,7 @@ impl FolderManager {
|
|||
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let setting = WorkspaceSettingPB {
|
||||
workspace_id,
|
||||
workspace_id: workspace_id.to_string(),
|
||||
latest_view: view,
|
||||
};
|
||||
send_current_workspace_notification(FolderNotification::DidUpdateWorkspaceSetting, setting);
|
||||
|
@ -1367,18 +1380,18 @@ impl FolderManager {
|
|||
let workspace_id = self.user.workspace_id()?;
|
||||
self
|
||||
.cloud_service
|
||||
.publish_view(workspace_id.as_str(), payload)
|
||||
.publish_view(&workspace_id, payload)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unpublish the view with the given view id.
|
||||
#[tracing::instrument(level = "debug", skip(self), err)]
|
||||
pub async fn unpublish_views(&self, view_ids: Vec<String>) -> FlowyResult<()> {
|
||||
pub async fn unpublish_views(&self, view_ids: Vec<Uuid>) -> FlowyResult<()> {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
self
|
||||
.cloud_service
|
||||
.unpublish_views(workspace_id.as_str(), view_ids)
|
||||
.unpublish_views(&workspace_id, view_ids)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1386,14 +1399,14 @@ impl FolderManager {
|
|||
/// Get the publish info of the view with the given view id.
|
||||
/// The publish info contains the namespace and publish_name of the view.
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
pub async fn get_publish_info(&self, view_id: &str) -> FlowyResult<PublishInfo> {
|
||||
pub async fn get_publish_info(&self, view_id: &Uuid) -> FlowyResult<PublishInfo> {
|
||||
let publish_info = self.cloud_service.get_publish_info(view_id).await?;
|
||||
Ok(publish_info)
|
||||
}
|
||||
|
||||
/// Sets the publish name of the view with the given view id.
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
pub async fn set_publish_name(&self, view_id: String, new_name: String) -> FlowyResult<()> {
|
||||
pub async fn set_publish_name(&self, view_id: Uuid, new_name: String) -> FlowyResult<()> {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
self
|
||||
.cloud_service
|
||||
|
@ -1409,7 +1422,7 @@ impl FolderManager {
|
|||
let workspace_id = self.user.workspace_id()?;
|
||||
self
|
||||
.cloud_service
|
||||
.set_publish_namespace(workspace_id.as_str(), new_namespace)
|
||||
.set_publish_namespace(&workspace_id, new_namespace)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1420,7 +1433,7 @@ impl FolderManager {
|
|||
let workspace_id = self.user.workspace_id()?;
|
||||
let namespace = self
|
||||
.cloud_service
|
||||
.get_publish_namespace(workspace_id.as_str())
|
||||
.get_publish_namespace(&workspace_id)
|
||||
.await?;
|
||||
Ok(namespace)
|
||||
}
|
||||
|
@ -1502,7 +1515,7 @@ impl FolderManager {
|
|||
};
|
||||
|
||||
if let Ok(payload) = self
|
||||
.get_publish_payload(¤t_view_id, publish_name, layout)
|
||||
.get_publish_payload(&Uuid::from_str(¤t_view_id)?, publish_name, layout)
|
||||
.await
|
||||
{
|
||||
payloads.push(payload);
|
||||
|
@ -1551,7 +1564,7 @@ impl FolderManager {
|
|||
|
||||
async fn get_publish_payload(
|
||||
&self,
|
||||
view_id: &str,
|
||||
view_id: &Uuid,
|
||||
publish_name: Option<String>,
|
||||
layout: ViewLayout,
|
||||
) -> FlowyResult<PublishPayload> {
|
||||
|
@ -1559,18 +1572,20 @@ impl FolderManager {
|
|||
let encoded_collab_wrapper: GatherEncodedCollab = handler
|
||||
.gather_publish_encode_collab(&self.user, view_id)
|
||||
.await?;
|
||||
let view = self.get_view_pb(view_id).await?;
|
||||
|
||||
let view_str_id = view_id.to_string();
|
||||
let view = self.get_view_pb(&view_str_id).await?;
|
||||
|
||||
let publish_name = publish_name.unwrap_or_else(|| generate_publish_name(&view.id, &view.name));
|
||||
|
||||
let child_views = self
|
||||
.build_publish_views(view_id)
|
||||
.build_publish_views(&view_str_id)
|
||||
.await
|
||||
.and_then(|v| v.child_views)
|
||||
.unwrap_or_default();
|
||||
|
||||
let ancestor_views = self
|
||||
.get_view_ancestors_pb(view_id)
|
||||
.get_view_ancestors_pb(&view_str_id)
|
||||
.await?
|
||||
.iter()
|
||||
.map(view_pb_to_publish_view)
|
||||
|
@ -1720,8 +1735,9 @@ impl FolderManager {
|
|||
};
|
||||
|
||||
if let Some(view) = view {
|
||||
let view_id = Uuid::from_str(view_id)?;
|
||||
if let Ok(handler) = self.get_handler(&view.layout) {
|
||||
handler.delete_view(view_id).await?;
|
||||
handler.delete_view(&view_id).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1733,11 +1749,11 @@ impl FolderManager {
|
|||
#[instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn import_single_file(
|
||||
&self,
|
||||
parent_view_id: String,
|
||||
parent_view_id: Uuid,
|
||||
import_data: ImportItem,
|
||||
) -> FlowyResult<(View, Vec<(String, CollabType, EncodedCollab)>)> {
|
||||
let handler = self.get_handler(&import_data.view_layout)?;
|
||||
let view_id = gen_view_id().to_string();
|
||||
let view_id = gen_view_id();
|
||||
let uid = self.user.user_id()?;
|
||||
let mut encoded_collab = vec![];
|
||||
|
||||
|
@ -1745,7 +1761,7 @@ impl FolderManager {
|
|||
match import_data.data {
|
||||
ImportData::FilePath { file_path } => {
|
||||
handler
|
||||
.import_from_file_path(&view_id, &import_data.name, file_path)
|
||||
.import_from_file_path(&view_id.to_string(), &import_data.name, file_path)
|
||||
.await?;
|
||||
},
|
||||
ImportData::Bytes { bytes } => {
|
||||
|
@ -1804,11 +1820,13 @@ impl FolderManager {
|
|||
views.push(view_pb_without_child_views(view));
|
||||
|
||||
for (object_id, collab_type, encode_collab) in encoded_collabs {
|
||||
match self.get_folder_collab_params(object_id, collab_type, encode_collab) {
|
||||
Ok(params) => objects.push(params),
|
||||
Err(e) => {
|
||||
error!("import error {}", e);
|
||||
},
|
||||
if let Ok(object_id) = Uuid::from_str(&object_id) {
|
||||
match self.get_folder_collab_params(object_id, collab_type, encode_collab) {
|
||||
Ok(params) => objects.push(params),
|
||||
Err(e) => {
|
||||
error!("import error {}", e);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1822,7 +1840,7 @@ impl FolderManager {
|
|||
// Notify that the parent view has changed
|
||||
if let Some(lock) = self.mutex_folder.load_full() {
|
||||
let folder = lock.read().await;
|
||||
notify_parent_view_did_change(&workspace_id, &folder, vec![import_data.parent_view_id]);
|
||||
notify_parent_view_did_change(workspace_id, &folder, vec![import_data.parent_view_id]);
|
||||
}
|
||||
|
||||
Ok(RepeatedViewPB { items: views })
|
||||
|
@ -1887,7 +1905,7 @@ impl FolderManager {
|
|||
|
||||
fn get_folder_collab_params(
|
||||
&self,
|
||||
object_id: String,
|
||||
object_id: Uuid,
|
||||
collab_type: CollabType,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> FlowyResult<FolderCollabParams> {
|
||||
|
@ -1911,18 +1929,20 @@ impl FolderManager {
|
|||
let folder = lock.read().await;
|
||||
let view = folder.get_view(view_id)?;
|
||||
match folder.get_view(&view.parent_view_id) {
|
||||
None => folder.get_workspace_info(&workspace_id).map(|workspace| {
|
||||
(
|
||||
true,
|
||||
workspace.id,
|
||||
workspace
|
||||
.child_views
|
||||
.items
|
||||
.into_iter()
|
||||
.map(|view| view.id)
|
||||
.collect::<Vec<String>>(),
|
||||
)
|
||||
}),
|
||||
None => folder
|
||||
.get_workspace_info(&workspace_id.to_string())
|
||||
.map(|workspace| {
|
||||
(
|
||||
true,
|
||||
workspace.id,
|
||||
workspace
|
||||
.child_views
|
||||
.items
|
||||
.into_iter()
|
||||
.map(|view| view.id)
|
||||
.collect::<Vec<String>>(),
|
||||
)
|
||||
}),
|
||||
Some(parent_view) => Some((
|
||||
false,
|
||||
parent_view.id.clone(),
|
||||
|
@ -2031,17 +2051,17 @@ impl FolderManager {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn remove_indices_for_workspace(&self, workspace_id: String) -> FlowyResult<()> {
|
||||
pub fn remove_indices_for_workspace(&self, workspace_id: &Uuid) -> FlowyResult<()> {
|
||||
self
|
||||
.folder_indexer
|
||||
.remove_indices_for_workspace(workspace_id)?;
|
||||
.remove_indices_for_workspace(workspace_id.clone())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
|
||||
pub(crate) fn get_workspace_public_view_pbs(workspace_id: &Uuid, folder: &Folder) -> Vec<ViewPB> {
|
||||
// get the trash ids
|
||||
let trash_ids = folder
|
||||
.get_all_trash_sections()
|
||||
|
@ -2056,7 +2076,7 @@ pub(crate) fn get_workspace_public_view_pbs(workspace_id: &str, folder: &Folder)
|
|||
.map(|view| view.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let mut views = folder.get_views_belong_to(workspace_id);
|
||||
let mut views = folder.get_views_belong_to(&workspace_id.to_string());
|
||||
// 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));
|
||||
|
||||
|
@ -2082,7 +2102,7 @@ fn get_all_child_view_ids(folder: &Folder, view_id: &str) -> Vec<String> {
|
|||
}
|
||||
|
||||
/// Get the current private views of the user.
|
||||
pub(crate) fn get_workspace_private_view_pbs(workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
|
||||
pub(crate) fn get_workspace_private_view_pbs(workspace_id: &Uuid, folder: &Folder) -> Vec<ViewPB> {
|
||||
// get the trash ids
|
||||
let trash_ids = folder
|
||||
.get_all_trash_sections()
|
||||
|
@ -2097,7 +2117,7 @@ pub(crate) fn get_workspace_private_view_pbs(workspace_id: &str, folder: &Folder
|
|||
.map(|view| view.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let mut views = folder.get_views_belong_to(workspace_id);
|
||||
let mut views = folder.get_views_belong_to(&workspace_id.to_string());
|
||||
// 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));
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use flowy_error::{FlowyError, FlowyResult};
|
|||
use std::sync::{Arc, Weak};
|
||||
use tokio::task::spawn_blocking;
|
||||
use tracing::{event, info, Level};
|
||||
use uuid::Uuid;
|
||||
|
||||
impl FolderManager {
|
||||
/// Called immediately after the application launched if the user already sign in/sign up.
|
||||
|
@ -17,7 +18,7 @@ impl FolderManager {
|
|||
pub async fn initialize(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
initial_data: FolderInitDataSource,
|
||||
) -> FlowyResult<()> {
|
||||
// Update the workspace id
|
||||
|
@ -37,7 +38,6 @@ impl FolderManager {
|
|||
);
|
||||
}
|
||||
|
||||
let workspace_id = workspace_id.to_string();
|
||||
// Get the collab db for the user with given user id.
|
||||
let collab_db = self.user.collab_db(uid)?;
|
||||
|
||||
|
@ -54,20 +54,20 @@ impl FolderManager {
|
|||
} => {
|
||||
let is_exist = self
|
||||
.user
|
||||
.is_folder_exist_on_disk(uid, &workspace_id)
|
||||
.is_folder_exist_on_disk(uid, workspace_id)
|
||||
.unwrap_or(false);
|
||||
// 1. if the folder exists, open it from local disk
|
||||
if is_exist {
|
||||
event!(Level::INFO, "Init folder from local disk");
|
||||
self
|
||||
.make_folder(uid, &workspace_id, collab_db, None, folder_notifier)
|
||||
.make_folder(uid, workspace_id, collab_db, None, folder_notifier)
|
||||
.await?
|
||||
} else if create_if_not_exist {
|
||||
// 2. if the folder doesn't exist and create_if_not_exist is true, create a default folder
|
||||
// Currently, this branch is only used when the server type is supabase. For appflowy cloud,
|
||||
// the default workspace is already created when the user sign up.
|
||||
self
|
||||
.create_default_folder(uid, &workspace_id, collab_db, folder_notifier)
|
||||
.create_default_folder(uid, workspace_id, collab_db, folder_notifier)
|
||||
.await?
|
||||
} else {
|
||||
// 3. If the folder doesn't exist and create_if_not_exist is false, try to fetch the folder data from cloud/
|
||||
|
@ -147,7 +147,7 @@ impl FolderManager {
|
|||
async fn create_default_folder(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
collab_db: Weak<CollabKVDB>,
|
||||
folder_notifier: FolderNotify,
|
||||
) -> Result<Arc<RwLock<Folder>>, FlowyError> {
|
||||
|
@ -170,24 +170,22 @@ impl FolderManager {
|
|||
Ok(folder)
|
||||
}
|
||||
|
||||
fn handle_index_folder(&self, workspace_id: String, folder: &Folder) {
|
||||
fn handle_index_folder(&self, workspace_id: Uuid, folder: &Folder) {
|
||||
let mut index_all = true;
|
||||
|
||||
let encoded_collab = self
|
||||
.store_preferences
|
||||
.get_object::<EncodedCollab>(&workspace_id);
|
||||
.get_object::<EncodedCollab>(workspace_id.to_string().as_str());
|
||||
|
||||
if let Some(encoded_collab) = encoded_collab {
|
||||
if let Ok(changes) = folder.calculate_view_changes(encoded_collab) {
|
||||
let folder_indexer = self.folder_indexer.clone();
|
||||
|
||||
let views = folder.get_all_views();
|
||||
let wid = workspace_id.clone();
|
||||
|
||||
if !changes.is_empty() && !views.is_empty() {
|
||||
spawn_blocking(move || {
|
||||
// We index the changes
|
||||
folder_indexer.index_view_changes(views, changes, wid);
|
||||
folder_indexer.index_view_changes(views, changes, workspace_id);
|
||||
});
|
||||
index_all = false;
|
||||
}
|
||||
|
@ -197,15 +195,13 @@ impl FolderManager {
|
|||
if index_all {
|
||||
let views = folder.get_all_views();
|
||||
let folder_indexer = self.folder_indexer.clone();
|
||||
let wid = workspace_id.clone();
|
||||
|
||||
// We spawn a blocking task to index all views in the folder
|
||||
spawn_blocking(move || {
|
||||
// We remove old indexes just in case
|
||||
let _ = folder_indexer.remove_indices_for_workspace(wid.clone());
|
||||
let _ = folder_indexer.remove_indices_for_workspace(workspace_id.clone());
|
||||
|
||||
// We index all views from the workspace
|
||||
folder_indexer.index_all_views(views, wid);
|
||||
folder_indexer.index_all_views(views, workspace_id);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -13,14 +13,16 @@ use collab_folder::{
|
|||
use lib_infra::sync_trace;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Weak;
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::{event, trace, Level};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Listen on the [ViewChange] after create/delete/update events happened
|
||||
pub(crate) fn subscribe_folder_view_changed(
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
mut rx: ViewChangeReceiver,
|
||||
weak_mutex_folder: Weak<RwLock<Folder>>,
|
||||
user: Weak<dyn FolderUser>,
|
||||
|
@ -46,9 +48,10 @@ pub(crate) fn subscribe_folder_view_changed(
|
|||
ChildViewChangeReason::Create,
|
||||
);
|
||||
let folder = lock.read().await;
|
||||
let parent_view_id = view.parent_view_id.clone();
|
||||
notify_parent_view_did_change(&workspace_id, &folder, vec![parent_view_id]);
|
||||
sync_trace!("[Folder] create view: {:?}", view);
|
||||
if let Ok(parent_view_id) = Uuid::from_str(&view.parent_view_id) {
|
||||
notify_parent_view_did_change(workspace_id, &folder, vec![parent_view_id]);
|
||||
sync_trace!("[Folder] create view: {:?}", view);
|
||||
}
|
||||
},
|
||||
ViewChange::DidDeleteView { views } => {
|
||||
for view in views {
|
||||
|
@ -69,7 +72,9 @@ pub(crate) fn subscribe_folder_view_changed(
|
|||
ChildViewChangeReason::Update,
|
||||
);
|
||||
let folder = lock.read().await;
|
||||
notify_parent_view_did_change(&workspace_id, &folder, vec![view.parent_view_id]);
|
||||
if let Ok(parent_view_id) = Uuid::from_str(&view.parent_view_id) {
|
||||
notify_parent_view_did_change(workspace_id, &folder, vec![parent_view_id]);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -78,7 +83,7 @@ pub(crate) fn subscribe_folder_view_changed(
|
|||
}
|
||||
|
||||
pub(crate) fn subscribe_folder_sync_state_changed(
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
mut folder_sync_state_rx: WatchStream<SyncState>,
|
||||
user: Weak<dyn FolderUser>,
|
||||
) {
|
||||
|
@ -93,16 +98,19 @@ pub(crate) fn subscribe_folder_sync_state_changed(
|
|||
}
|
||||
}
|
||||
|
||||
folder_notification_builder(&workspace_id, FolderNotification::DidUpdateFolderSyncUpdate)
|
||||
.payload(FolderSyncStatePB::from(state))
|
||||
.send();
|
||||
folder_notification_builder(
|
||||
&workspace_id.to_string(),
|
||||
FolderNotification::DidUpdateFolderSyncUpdate,
|
||||
)
|
||||
.payload(FolderSyncStatePB::from(state))
|
||||
.send();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Listen on the [TrashChange]s and notify the frontend some views were changed.
|
||||
pub(crate) fn subscribe_folder_trash_changed(
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
mut rx: SectionChangeReceiver,
|
||||
weak_mutex_folder: Weak<RwLock<Folder>>,
|
||||
user: Weak<dyn FolderUser>,
|
||||
|
@ -131,7 +139,9 @@ pub(crate) fn subscribe_folder_trash_changed(
|
|||
let folder = lock.read().await;
|
||||
let views = folder.get_views(&ids);
|
||||
for view in views {
|
||||
unique_ids.insert(view.parent_view_id.clone());
|
||||
if let Ok(parent_view_id) = Uuid::from_str(&view.parent_view_id) {
|
||||
unique_ids.insert(parent_view_id);
|
||||
}
|
||||
}
|
||||
|
||||
let repeated_trash: RepeatedTrashPB = folder.get_my_trash_info().into();
|
||||
|
@ -140,7 +150,7 @@ pub(crate) fn subscribe_folder_trash_changed(
|
|||
.send();
|
||||
|
||||
let parent_view_ids = unique_ids.into_iter().collect();
|
||||
notify_parent_view_did_change(&workspace_id, &folder, parent_view_ids);
|
||||
notify_parent_view_did_change(workspace_id, &folder, parent_view_ids);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -150,10 +160,10 @@ pub(crate) fn subscribe_folder_trash_changed(
|
|||
|
||||
/// Notify the list of parent view ids that its child views were changed.
|
||||
#[tracing::instrument(level = "debug", skip(folder, parent_view_ids))]
|
||||
pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
|
||||
workspace_id: &str,
|
||||
pub(crate) fn notify_parent_view_did_change(
|
||||
workspace_id: Uuid,
|
||||
folder: &Folder,
|
||||
parent_view_ids: Vec<T>,
|
||||
parent_view_ids: Vec<Uuid>,
|
||||
) -> Option<()> {
|
||||
let trash_ids = folder
|
||||
.get_all_trash_sections()
|
||||
|
@ -162,24 +172,23 @@ pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
|
|||
.collect::<Vec<String>>();
|
||||
|
||||
for parent_view_id in parent_view_ids {
|
||||
let parent_view_id = parent_view_id.as_ref();
|
||||
|
||||
// if the view's parent id equal to workspace id. Then it will fetch the current
|
||||
// workspace views. Because the workspace is not a view stored in the views map.
|
||||
if parent_view_id == workspace_id {
|
||||
notify_did_update_workspace(workspace_id, folder);
|
||||
notify_did_update_section_views(workspace_id, folder);
|
||||
notify_did_update_workspace(&workspace_id, folder);
|
||||
notify_did_update_section_views(&workspace_id, folder);
|
||||
} else {
|
||||
// Parent view can contain a list of child views. Currently, only get the first level
|
||||
// child views.
|
||||
let parent_view = folder.get_view(parent_view_id)?;
|
||||
let mut child_views = folder.get_views_belong_to(parent_view_id);
|
||||
let parent_view_id = parent_view_id.to_string();
|
||||
let parent_view = folder.get_view(&parent_view_id)?;
|
||||
let mut child_views = folder.get_views_belong_to(&parent_view_id);
|
||||
child_views.retain(|view| !trash_ids.contains(&view.id));
|
||||
event!(Level::DEBUG, child_views_count = child_views.len());
|
||||
|
||||
// Post the notification
|
||||
let parent_view_pb = view_pb_with_child_views(parent_view, child_views);
|
||||
folder_notification_builder(parent_view_id, FolderNotification::DidUpdateView)
|
||||
folder_notification_builder(&parent_view_id, FolderNotification::DidUpdateView)
|
||||
.payload(parent_view_pb)
|
||||
.send();
|
||||
}
|
||||
|
@ -188,7 +197,7 @@ pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
|
|||
None
|
||||
}
|
||||
|
||||
pub(crate) fn notify_did_update_section_views(workspace_id: &str, folder: &Folder) {
|
||||
pub(crate) fn notify_did_update_section_views(workspace_id: &Uuid, folder: &Folder) {
|
||||
let public_views = get_workspace_public_view_pbs(workspace_id, folder);
|
||||
let private_views = get_workspace_private_view_pbs(workspace_id, folder);
|
||||
trace!(
|
||||
|
@ -214,7 +223,7 @@ pub(crate) fn notify_did_update_section_views(workspace_id: &str, folder: &Folde
|
|||
.send();
|
||||
}
|
||||
|
||||
pub(crate) fn notify_did_update_workspace(workspace_id: &str, folder: &Folder) {
|
||||
pub(crate) fn notify_did_update_workspace(workspace_id: &Uuid, folder: &Folder) {
|
||||
let repeated_view: RepeatedViewPB = get_workspace_public_view_pbs(workspace_id, folder).into();
|
||||
folder_notification_builder(workspace_id, FolderNotification::DidUpdateWorkspaceViews)
|
||||
.payload(repeated_view)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use flowy_derive::ProtoBuf_Enum;
|
||||
use flowy_notification::NotificationBuilder;
|
||||
use lib_dispatch::prelude::ToBytes;
|
||||
use tracing::trace;
|
||||
|
||||
const FOLDER_OBSERVABLE_SOURCE: &str = "Workspace";
|
||||
|
||||
|
@ -68,9 +69,14 @@ impl std::convert::From<i32> for FolderNotification {
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace")]
|
||||
pub(crate) fn folder_notification_builder(id: &str, ty: FolderNotification) -> NotificationBuilder {
|
||||
NotificationBuilder::new(id, ty, FOLDER_OBSERVABLE_SOURCE)
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
pub(crate) fn folder_notification_builder<T: ToString>(
|
||||
id: T,
|
||||
ty: FolderNotification,
|
||||
) -> NotificationBuilder {
|
||||
let id = id.to_string();
|
||||
trace!("folder_notification_builder: id = {id}, ty = {ty:?}");
|
||||
NotificationBuilder::new(&id, ty, FOLDER_OBSERVABLE_SOURCE)
|
||||
}
|
||||
|
||||
/// The [CURRENT_WORKSPACE] represents as the current workspace that opened by the
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use collab_folder::ViewLayout;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ImportType {
|
||||
|
@ -35,6 +36,6 @@ impl Display for ImportData {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ImportParams {
|
||||
pub parent_view_id: String,
|
||||
pub parent_view_id: Uuid,
|
||||
pub items: Vec<ImportItem>,
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::entities::UserFolderPB;
|
||||
use flowy_error::{ErrorCode, FlowyError};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) fn folder_not_init_error() -> FlowyError {
|
||||
FlowyError::internal().with_context("Folder not initialized")
|
||||
}
|
||||
|
||||
pub(crate) fn workspace_data_not_sync_error(uid: i64, workspace_id: &str) -> FlowyError {
|
||||
pub(crate) fn workspace_data_not_sync_error(uid: i64, workspace_id: &Uuid) -> FlowyError {
|
||||
FlowyError::from(ErrorCode::WorkspaceDataNotSync).with_payload(UserFolderPB {
|
||||
uid,
|
||||
workspace_id: workspace_id.to_string(),
|
||||
|
|
|
@ -6,11 +6,11 @@ use collab_folder::hierarchy_builder::NestedViewBuilder;
|
|||
pub use collab_folder::View;
|
||||
use collab_folder::ViewLayout;
|
||||
use dashmap::DashMap;
|
||||
use flowy_error::FlowyError;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use uuid::Uuid;
|
||||
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
|
@ -51,23 +51,23 @@ pub trait FolderOperationHandler: Send + Sync {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError>;
|
||||
async fn open_view(&self, view_id: &Uuid) -> Result<(), FlowyError>;
|
||||
/// Closes the view and releases the resources that this view has in
|
||||
/// the backend
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError>;
|
||||
async fn close_view(&self, view_id: &Uuid) -> Result<(), FlowyError>;
|
||||
|
||||
/// Called when the view is deleted.
|
||||
/// This will called after the view is deleted from the trash.
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError>;
|
||||
async fn delete_view(&self, view_id: &Uuid) -> Result<(), FlowyError>;
|
||||
|
||||
/// Returns the [ViewData] that can be used to create the same view.
|
||||
async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError>;
|
||||
async fn duplicate_view(&self, view_id: &Uuid) -> Result<Bytes, FlowyError>;
|
||||
|
||||
/// get the encoded collab data from the disk.
|
||||
async fn gather_publish_encode_collab(
|
||||
&self,
|
||||
_user: &Arc<dyn FolderUser>,
|
||||
_view_id: &str,
|
||||
_view_id: &Uuid,
|
||||
) -> Result<GatherEncodedCollab, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
|
@ -102,8 +102,8 @@ pub trait FolderOperationHandler: Send + Sync {
|
|||
async fn create_default_view(
|
||||
&self,
|
||||
user_id: i64,
|
||||
parent_view_id: &str,
|
||||
view_id: &str,
|
||||
parent_view_id: &Uuid,
|
||||
view_id: &Uuid,
|
||||
name: &str,
|
||||
layout: ViewLayout,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
@ -114,7 +114,7 @@ pub trait FolderOperationHandler: Send + Sync {
|
|||
async fn import_from_bytes(
|
||||
&self,
|
||||
uid: i64,
|
||||
view_id: &str,
|
||||
view_id: &Uuid,
|
||||
name: &str,
|
||||
import_type: ImportType,
|
||||
bytes: Vec<u8>,
|
||||
|
@ -152,8 +152,8 @@ impl From<ViewLayoutPB> for ViewLayout {
|
|||
pub(crate) fn create_view(uid: i64, params: CreateViewParams, layout: ViewLayout) -> View {
|
||||
let time = timestamp();
|
||||
View {
|
||||
id: params.view_id,
|
||||
parent_view_id: params.parent_view_id,
|
||||
id: params.view_id.to_string(),
|
||||
parent_view_id: params.parent_view_id.to_string(),
|
||||
name: params.name,
|
||||
created_at: time,
|
||||
is_favorite: false,
|
||||
|
|
|
@ -11,4 +11,4 @@ collab = { workspace = true }
|
|||
collab-folder = { workspace = true }
|
||||
flowy-error = { workspace = true }
|
||||
client-api = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
uuid.workspace = true
|
|
@ -1,12 +1,13 @@
|
|||
use client_api::entity::search_dto::SearchDocumentResponseItem;
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[async_trait]
|
||||
pub trait SearchCloudService: Send + Sync + 'static {
|
||||
async fn document_search(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
query: String,
|
||||
) -> Result<Vec<SearchDocumentResponseItem>, FlowyError>;
|
||||
}
|
||||
|
|
|
@ -4,44 +4,45 @@ use std::sync::Arc;
|
|||
use collab::core::collab::IndexContentReceiver;
|
||||
use collab_folder::{folder_diff::FolderViewChange, View, ViewIcon, ViewLayout};
|
||||
use flowy_error::FlowyError;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct IndexableData {
|
||||
pub id: String,
|
||||
pub data: String,
|
||||
pub icon: Option<ViewIcon>,
|
||||
pub layout: ViewLayout,
|
||||
pub workspace_id: String,
|
||||
pub workspace_id: Uuid,
|
||||
}
|
||||
|
||||
impl IndexableData {
|
||||
pub fn from_view(view: Arc<View>, workspace_id: String) -> Self {
|
||||
pub fn from_view(view: Arc<View>, workspace_id: Uuid) -> Self {
|
||||
IndexableData {
|
||||
id: view.id.clone(),
|
||||
data: view.name.clone(),
|
||||
icon: view.icon.clone(),
|
||||
layout: view.layout.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
workspace_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IndexManager: Send + Sync {
|
||||
fn set_index_content_receiver(&self, rx: IndexContentReceiver, workspace_id: String);
|
||||
fn set_index_content_receiver(&self, rx: IndexContentReceiver, workspace_id: Uuid);
|
||||
fn add_index(&self, data: IndexableData) -> Result<(), FlowyError>;
|
||||
fn update_index(&self, data: IndexableData) -> Result<(), FlowyError>;
|
||||
fn remove_indices(&self, ids: Vec<String>) -> Result<(), FlowyError>;
|
||||
fn remove_indices_for_workspace(&self, workspace_id: String) -> Result<(), FlowyError>;
|
||||
fn remove_indices_for_workspace(&self, workspace_id: Uuid) -> Result<(), FlowyError>;
|
||||
fn is_indexed(&self) -> bool;
|
||||
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
}
|
||||
|
||||
pub trait FolderIndexManager: IndexManager {
|
||||
fn index_all_views(&self, views: Vec<Arc<View>>, workspace_id: String);
|
||||
fn index_all_views(&self, views: Vec<Arc<View>>, workspace_id: Uuid);
|
||||
fn index_view_changes(
|
||||
&self,
|
||||
views: Vec<Arc<View>>,
|
||||
changes: Vec<FolderViewChange>,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ flowy-error = { workspace = true, features = [
|
|||
"impl_from_serde",
|
||||
] }
|
||||
flowy-notification.workspace = true
|
||||
flowy-sqlite.workspace = true
|
||||
flowy-user.workspace = true
|
||||
flowy-search-pub.workspace = true
|
||||
flowy-folder = { workspace = true }
|
||||
|
@ -37,12 +36,7 @@ async-stream = "0.3.4"
|
|||
strsim = "0.11.0"
|
||||
strum_macros = "0.26.1"
|
||||
tantivy = { version = "0.22.0" }
|
||||
tempfile = "3.9.0"
|
||||
validator = { workspace = true, features = ["derive"] }
|
||||
|
||||
diesel.workspace = true
|
||||
diesel_derives = { version = "2.1.0", features = ["sqlite", "r2d2"] }
|
||||
diesel_migrations = { version = "2.1.0", features = ["sqlite"] }
|
||||
uuid.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
flowy-codegen.workspace = true
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use std::sync::Arc;
|
||||
use tracing::{trace, warn};
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_folder::{manager::FolderManager, ViewLayout};
|
||||
use flowy_search_pub::cloud::SearchCloudService;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use tracing::{trace, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
entities::{IndexTypePB, ResultIconPB, ResultIconTypePB, SearchFilterPB, SearchResultPB},
|
||||
|
@ -49,6 +50,7 @@ impl SearchHandler for DocumentSearchHandler {
|
|||
None => return Ok(vec![]),
|
||||
};
|
||||
|
||||
let workspace_id = Uuid::from_str(&workspace_id)?;
|
||||
let results = self
|
||||
.cloud_service
|
||||
.document_search(&workspace_id, query)
|
||||
|
@ -61,7 +63,7 @@ impl SearchHandler for DocumentSearchHandler {
|
|||
let mut search_results: Vec<SearchResultPB> = vec![];
|
||||
|
||||
for result in results {
|
||||
if let Some(view) = views.iter().find(|v| v.id == result.object_id) {
|
||||
if let Some(view) = views.iter().find(|v| v.id == result.object_id.to_string()) {
|
||||
// If there is no View for the result, we don't add it to the results
|
||||
// If possible we will extract the icon to display for the result
|
||||
let icon: Option<ResultIconPB> = match view.icon.clone() {
|
||||
|
@ -77,12 +79,12 @@ impl SearchHandler for DocumentSearchHandler {
|
|||
|
||||
search_results.push(SearchResultPB {
|
||||
index_type: IndexTypePB::Document,
|
||||
view_id: result.object_id.clone(),
|
||||
id: result.object_id.clone(),
|
||||
view_id: result.object_id.to_string(),
|
||||
id: result.object_id.to_string(),
|
||||
data: view.name.clone(),
|
||||
icon,
|
||||
score: result.score,
|
||||
workspace_id: result.workspace_id,
|
||||
workspace_id: result.workspace_id.to_string(),
|
||||
preview: result.preview,
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -20,13 +20,13 @@ use flowy_error::{FlowyError, FlowyResult};
|
|||
use flowy_search_pub::entities::{FolderIndexManager, IndexManager, IndexableData};
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
|
||||
use super::entities::FolderIndexData;
|
||||
use strsim::levenshtein;
|
||||
use tantivy::{
|
||||
collector::TopDocs, directory::MmapDirectory, doc, query::QueryParser, schema::Field, Document,
|
||||
Index, IndexReader, IndexWriter, TantivyDocument, Term,
|
||||
};
|
||||
|
||||
use super::entities::FolderIndexData;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FolderIndexManagerImpl {
|
||||
|
@ -139,7 +139,7 @@ impl FolderIndexManagerImpl {
|
|||
title_field => data.data.clone(),
|
||||
icon_field => icon.unwrap_or_default(),
|
||||
icon_ty_field => icon_ty,
|
||||
workspace_id_field => data.workspace_id.clone(),
|
||||
workspace_id_field => data.workspace_id.to_string(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -293,7 +293,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn set_index_content_receiver(&self, mut rx: IndexContentReceiver, workspace_id: String) {
|
||||
fn set_index_content_receiver(&self, mut rx: IndexContentReceiver, workspace_id: Uuid) {
|
||||
let indexer = self.clone();
|
||||
let wid = workspace_id.clone();
|
||||
tokio::spawn(async move {
|
||||
|
@ -352,7 +352,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
|||
title_field => data.data,
|
||||
icon_field => icon.unwrap_or_default(),
|
||||
icon_ty_field => icon_ty,
|
||||
workspace_id_field => data.workspace_id.clone(),
|
||||
workspace_id_field => data.workspace_id.to_string(),
|
||||
]);
|
||||
|
||||
index_writer.commit()?;
|
||||
|
@ -389,7 +389,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
|||
title_field => data.data,
|
||||
icon_field => icon.unwrap_or_default(),
|
||||
icon_ty_field => icon_ty,
|
||||
workspace_id_field => data.workspace_id,
|
||||
workspace_id_field => data.workspace_id.to_string(),
|
||||
]);
|
||||
|
||||
index_writer.commit()?;
|
||||
|
@ -400,14 +400,14 @@ impl IndexManager for FolderIndexManagerImpl {
|
|||
/// Removes all indexes that are related by workspace id. This is useful
|
||||
/// for cleaning indexes when eg. removing/leaving a workspace.
|
||||
///
|
||||
fn remove_indices_for_workspace(&self, workspace_id: String) -> Result<(), FlowyError> {
|
||||
fn remove_indices_for_workspace(&self, workspace_id: Uuid) -> Result<(), FlowyError> {
|
||||
let mut index_writer = self.get_index_writer()?;
|
||||
|
||||
let folder_schema = self.get_folder_schema()?;
|
||||
let id_field = folder_schema
|
||||
.schema
|
||||
.get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?;
|
||||
let delete_term = Term::from_field_text(id_field, &workspace_id);
|
||||
let delete_term = Term::from_field_text(id_field, &workspace_id.to_string());
|
||||
index_writer.delete_term(delete_term);
|
||||
|
||||
index_writer.commit()?;
|
||||
|
@ -421,7 +421,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
|||
}
|
||||
|
||||
impl FolderIndexManager for FolderIndexManagerImpl {
|
||||
fn index_all_views(&self, views: Vec<Arc<View>>, workspace_id: String) {
|
||||
fn index_all_views(&self, views: Vec<Arc<View>>, workspace_id: Uuid) {
|
||||
let indexable_data = views
|
||||
.into_iter()
|
||||
.map(|view| IndexableData::from_view(view, workspace_id.clone()))
|
||||
|
@ -434,7 +434,7 @@ impl FolderIndexManager for FolderIndexManagerImpl {
|
|||
&self,
|
||||
views: Vec<Arc<View>>,
|
||||
changes: Vec<FolderViewChange>,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) {
|
||||
let mut views_iter = views.into_iter();
|
||||
for change in changes {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use flowy_error::FlowyResult;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub const USER_SIGN_IN_URL: &str = "sign_in_url";
|
||||
pub const USER_UUID: &str = "uuid";
|
||||
|
@ -8,5 +9,5 @@ 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>;
|
||||
fn workspace_id(&self) -> FlowyResult<Uuid>;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ use serde_json::Value;
|
|||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use tracing::trace;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) struct AFCloudChatCloudServiceImpl<T> {
|
||||
pub inner: T,
|
||||
|
@ -30,10 +31,10 @@ where
|
|||
{
|
||||
async fn create_chat(
|
||||
&self,
|
||||
_uid: &i64,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
rag_ids: Vec<String>,
|
||||
uid: &i64,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let chat_id = chat_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
|
@ -52,13 +53,12 @@ where
|
|||
|
||||
async fn create_question(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
message_type: ChatMessageType,
|
||||
metadata: &[ChatMessageMetadata],
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let chat_id = chat_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let params = CreateChatMessageParams {
|
||||
|
@ -68,7 +68,7 @@ where
|
|||
};
|
||||
|
||||
let message = try_get_client?
|
||||
.create_question(&workspace_id, &chat_id, params)
|
||||
.create_question(workspace_id, &chat_id, params)
|
||||
.await
|
||||
.map_err(FlowyError::from)?;
|
||||
Ok(message)
|
||||
|
@ -76,8 +76,8 @@ where
|
|||
|
||||
async fn create_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
question_id: i64,
|
||||
metadata: Option<serde_json::Value>,
|
||||
|
@ -89,7 +89,7 @@ where
|
|||
question_message_id: question_id,
|
||||
};
|
||||
let message = try_get_client?
|
||||
.save_answer(workspace_id, chat_id, params)
|
||||
.save_answer(workspace_id, chat_id.to_string().as_str(), params)
|
||||
.await
|
||||
.map_err(FlowyError::from)?;
|
||||
Ok(message)
|
||||
|
@ -97,8 +97,8 @@ where
|
|||
|
||||
async fn stream_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
format: ResponseFormat,
|
||||
ai_model: Option<AIModel>,
|
||||
|
@ -129,13 +129,17 @@ where
|
|||
|
||||
async fn get_answer(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
question_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let resp = try_get_client?
|
||||
.get_answer(workspace_id, chat_id, question_message_id)
|
||||
.get_answer(
|
||||
workspace_id,
|
||||
chat_id.to_string().as_str(),
|
||||
question_message_id,
|
||||
)
|
||||
.await
|
||||
.map_err(FlowyError::from)?;
|
||||
Ok(resp)
|
||||
|
@ -143,14 +147,14 @@ where
|
|||
|
||||
async fn get_chat_messages(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
offset: MessageCursor,
|
||||
limit: u64,
|
||||
) -> Result<RepeatedChatMessage, FlowyError> {
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let resp = try_get_client?
|
||||
.get_chat_messages(workspace_id, chat_id, offset, limit)
|
||||
.get_chat_messages(workspace_id, chat_id.to_string().as_str(), offset, limit)
|
||||
.await
|
||||
.map_err(FlowyError::from)?;
|
||||
|
||||
|
@ -159,13 +163,17 @@ where
|
|||
|
||||
async fn get_question_from_answer_id(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
answer_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
let try_get_client = self.inner.try_get_client()?;
|
||||
let resp = try_get_client
|
||||
.get_question_message_from_answer_id(workspace_id, chat_id, answer_message_id)
|
||||
.get_question_message_from_answer_id(
|
||||
workspace_id,
|
||||
chat_id.to_string().as_str(),
|
||||
answer_message_id,
|
||||
)
|
||||
.await
|
||||
.map_err(FlowyError::from)?
|
||||
.ok_or_else(FlowyError::record_not_found)?;
|
||||
|
@ -175,13 +183,13 @@ where
|
|||
|
||||
async fn get_related_message(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
) -> Result<RepeatedRelatedQuestion, FlowyError> {
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let resp = try_get_client?
|
||||
.get_chat_related_question(workspace_id, chat_id, message_id)
|
||||
.get_chat_related_question(workspace_id, chat_id.to_string().as_str(), message_id)
|
||||
.await
|
||||
.map_err(FlowyError::from)?;
|
||||
|
||||
|
@ -190,7 +198,7 @@ where
|
|||
|
||||
async fn stream_complete(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
params: CompleteTextParams,
|
||||
ai_model: Option<AIModel>,
|
||||
) -> Result<StreamComplete, FlowyError> {
|
||||
|
@ -207,10 +215,10 @@ where
|
|||
|
||||
async fn embed_file(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_file_path: &Path,
|
||||
_chat_id: &str,
|
||||
_metadata: Option<HashMap<String, Value>>,
|
||||
workspace_id: &Uuid,
|
||||
file_path: &Path,
|
||||
chat_id: &Uuid,
|
||||
metadata: Option<HashMap<String, Value>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
return Err(
|
||||
FlowyError::not_support()
|
||||
|
@ -218,7 +226,7 @@ where
|
|||
);
|
||||
}
|
||||
|
||||
async fn get_local_ai_config(&self, workspace_id: &str) -> Result<LocalAIConfig, FlowyError> {
|
||||
async fn get_local_ai_config(&self, workspace_id: &Uuid) -> Result<LocalAIConfig, FlowyError> {
|
||||
let system = get_operating_system();
|
||||
let platform = match system {
|
||||
OperatingSystem::MacOS => "macos",
|
||||
|
@ -232,51 +240,51 @@ where
|
|||
let config = self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
.get_local_ai_config(workspace_id, platform)
|
||||
.get_local_ai_config(workspace_id.to_string().as_str(), platform)
|
||||
.await?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
async fn get_workspace_plan(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<SubscriptionPlan>, FlowyError> {
|
||||
let plans = self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
.get_active_workspace_subscriptions(workspace_id)
|
||||
.get_active_workspace_subscriptions(workspace_id.to_string().as_str())
|
||||
.await?;
|
||||
Ok(plans)
|
||||
}
|
||||
|
||||
async fn get_chat_settings(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<ChatSettings, FlowyError> {
|
||||
let settings = self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
.get_chat_settings(workspace_id, chat_id)
|
||||
.get_chat_settings(workspace_id, chat_id.to_string().as_str())
|
||||
.await?;
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
async fn update_chat_settings(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
params: UpdateChatParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
.update_chat_settings(workspace_id, chat_id, params)
|
||||
.update_chat_settings(workspace_id, chat_id.to_string().as_str(), params)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_available_models(&self, workspace_id: &str) -> Result<ModelList, FlowyError> {
|
||||
async fn get_available_models(&self, workspace_id: &Uuid) -> Result<ModelList, FlowyError> {
|
||||
let list = self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
|
@ -285,11 +293,11 @@ where
|
|||
Ok(list)
|
||||
}
|
||||
|
||||
async fn get_workspace_default_model(&self, workspace_id: &str) -> Result<String, FlowyError> {
|
||||
async fn get_workspace_default_model(&self, workspace_id: &Uuid) -> Result<String, FlowyError> {
|
||||
let setting = self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
.get_workspace_settings(workspace_id)
|
||||
.get_workspace_settings(workspace_id.to_string().as_str())
|
||||
.await?;
|
||||
Ok(setting.ai_model)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
use crate::af_cloud::define::ServerUser;
|
||||
use crate::af_cloud::impls::util::check_request_workspace_id_is_match;
|
||||
use crate::af_cloud::AFServer;
|
||||
use client_api::entity::ai_dto::{
|
||||
SummarizeRowData, SummarizeRowParams, TranslateRowData, TranslateRowParams,
|
||||
};
|
||||
|
@ -6,20 +9,16 @@ use client_api::entity::{CreateCollabParams, QueryCollab, QueryCollabParams};
|
|||
use client_api::error::ErrorCode::RecordNotFound;
|
||||
use collab::entity::EncodedCollab;
|
||||
use collab_entity::CollabType;
|
||||
use serde_json::{Map, Value};
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, instrument};
|
||||
|
||||
use flowy_database_pub::cloud::{
|
||||
DatabaseAIService, DatabaseCloudService, DatabaseSnapshot, EncodeCollabByOid, SummaryRowContent,
|
||||
TranslateRowContent, TranslateRowResponse,
|
||||
};
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
use crate::af_cloud::impls::util::check_request_workspace_id_is_match;
|
||||
use crate::af_cloud::AFServer;
|
||||
use serde_json::{Map, Value};
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, instrument};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) struct AFCloudDatabaseCloudServiceImpl<T> {
|
||||
pub inner: T,
|
||||
|
@ -35,12 +34,10 @@ where
|
|||
#[allow(clippy::blocks_in_conditions)]
|
||||
async fn get_database_encode_collab(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let object_id = object_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
let params = QueryCollabParams {
|
||||
|
@ -51,7 +48,7 @@ where
|
|||
match result {
|
||||
Ok(data) => {
|
||||
check_request_workspace_id_is_match(
|
||||
&workspace_id,
|
||||
workspace_id,
|
||||
&cloned_user,
|
||||
format!("get database object: {}:{}", object_id, collab_type),
|
||||
)?;
|
||||
|
@ -71,17 +68,17 @@ where
|
|||
#[allow(clippy::blocks_in_conditions)]
|
||||
async fn create_database_encode_collab(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError> {
|
||||
let encoded_collab_v1 = encoded_collab
|
||||
.encode_to_bytes()
|
||||
.map_err(|err| FlowyError::internal().with_context(err))?;
|
||||
let params = CreateCollabParams {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
object_id: object_id.to_string(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
object_id: object_id.clone(),
|
||||
encoded_collab_v1,
|
||||
collab_type,
|
||||
};
|
||||
|
@ -92,11 +89,10 @@ where
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
async fn batch_get_database_encode_collab(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
object_ids: Vec<Uuid>,
|
||||
object_ty: CollabType,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<EncodeCollabByOid, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
let client = try_get_client?;
|
||||
|
@ -104,8 +100,8 @@ where
|
|||
.into_iter()
|
||||
.map(|object_id| QueryCollab::new(object_id, object_ty))
|
||||
.collect();
|
||||
let results = client.batch_get_collab(&workspace_id, params).await?;
|
||||
check_request_workspace_id_is_match(&workspace_id, &cloned_user, "batch get database object")?;
|
||||
let results = client.batch_get_collab(workspace_id, params).await?;
|
||||
check_request_workspace_id_is_match(workspace_id, &cloned_user, "batch get database object")?;
|
||||
Ok(
|
||||
results
|
||||
.0
|
||||
|
@ -131,8 +127,8 @@ where
|
|||
|
||||
async fn get_database_collab_object_snapshots(
|
||||
&self,
|
||||
_object_id: &str,
|
||||
_limit: usize,
|
||||
object_id: &Uuid,
|
||||
limit: usize,
|
||||
) -> Result<Vec<DatabaseSnapshot>, FlowyError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
@ -145,17 +141,17 @@ where
|
|||
{
|
||||
async fn summary_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
_object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
workspace_id: &Uuid,
|
||||
_object_id: &Uuid,
|
||||
_summary_row: SummaryRowContent,
|
||||
) -> Result<String, FlowyError> {
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let map: Map<String, Value> = summary_row
|
||||
let map: Map<String, Value> = _summary_row
|
||||
.into_iter()
|
||||
.map(|(key, value)| (key, Value::String(value)))
|
||||
.collect();
|
||||
let params = SummarizeRowParams {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
data: SummarizeRowData::Content(map),
|
||||
};
|
||||
let data = try_get_client?.summarize_row(params).await?;
|
||||
|
@ -164,19 +160,21 @@ where
|
|||
|
||||
async fn translate_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
translate_row: TranslateRowContent,
|
||||
language: &str,
|
||||
workspace_id: &Uuid,
|
||||
_translate_row: TranslateRowContent,
|
||||
_language: &str,
|
||||
) -> Result<TranslateRowResponse, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let data = TranslateRowData {
|
||||
cells: translate_row,
|
||||
language: language.to_string(),
|
||||
cells: _translate_row,
|
||||
language: _language.to_string(),
|
||||
include_header: false,
|
||||
};
|
||||
|
||||
let params = TranslateRowParams { workspace_id, data };
|
||||
let params = TranslateRowParams {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
data,
|
||||
};
|
||||
let data = try_get_client?.translate_row(params).await?;
|
||||
Ok(data)
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ use collab::entity::EncodedCollab;
|
|||
use collab::preclude::Collab;
|
||||
use collab_document::document::Document;
|
||||
use collab_entity::CollabType;
|
||||
use std::sync::Arc;
|
||||
use tracing::instrument;
|
||||
|
||||
use flowy_document_pub::cloud::*;
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::sync::Arc;
|
||||
use tracing::instrument;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
use crate::af_cloud::impls::util::check_request_workspace_id_is_match;
|
||||
|
@ -29,12 +29,12 @@ where
|
|||
#[instrument(level = "debug", skip_all, fields(document_id = %document_id))]
|
||||
async fn get_document_doc_state(
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let params = QueryCollabParams {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
inner: QueryCollab::new(document_id.to_string(), CollabType::Document),
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab::new(document_id.clone(), CollabType::Document),
|
||||
};
|
||||
let doc_state = self
|
||||
.inner
|
||||
|
@ -57,9 +57,9 @@ where
|
|||
|
||||
async fn get_document_snapshots(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
_limit: usize,
|
||||
_workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
limit: usize,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<DocumentSnapshot>, FlowyError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
@ -67,12 +67,12 @@ where
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
async fn get_document_data(
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<DocumentData>, FlowyError> {
|
||||
let params = QueryCollabParams {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
inner: QueryCollab::new(document_id.to_string(), CollabType::Document),
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab::new(document_id.clone(), CollabType::Document),
|
||||
};
|
||||
let doc_state = self
|
||||
.inner
|
||||
|
@ -89,7 +89,7 @@ where
|
|||
)?;
|
||||
let collab = Collab::new_with_source(
|
||||
CollabOrigin::Empty,
|
||||
document_id,
|
||||
document_id.to_string().as_str(),
|
||||
DataSource::DocStateV1(doc_state),
|
||||
vec![],
|
||||
false,
|
||||
|
@ -100,13 +100,13 @@ where
|
|||
|
||||
async fn create_document_collab(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
document_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
document_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError> {
|
||||
let params = CreateCollabParams {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
object_id: document_id.to_string(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
object_id: document_id.clone(),
|
||||
encoded_collab_v1: encoded_collab
|
||||
.encode_to_bytes()
|
||||
.map_err(|err| FlowyError::internal().with_context(err))?,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::af_cloud::AFServer;
|
||||
use client_api::entity::{CompleteUploadRequest, CreateUploadRequest};
|
||||
use flowy_error::{ErrorCode, FlowyError};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_storage_pub::cloud::{ObjectIdentity, ObjectValue, StorageCloudService};
|
||||
use flowy_storage_pub::storage::{CompletedPartRequest, CreateUploadResponse, UploadPartResponse};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct AFCloudFileStorageServiceImpl<T> {
|
||||
pub client: T,
|
||||
|
@ -56,10 +57,10 @@ where
|
|||
|
||||
async fn get_object_url_v1(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
file_id: &str,
|
||||
) -> Result<String, FlowyError> {
|
||||
) -> FlowyResult<String> {
|
||||
let url = self
|
||||
.client
|
||||
.try_get_client()?
|
||||
|
@ -67,14 +68,14 @@ where
|
|||
Ok(url)
|
||||
}
|
||||
|
||||
async fn parse_object_url_v1(&self, url: &str) -> Option<(String, String, String)> {
|
||||
async fn parse_object_url_v1(&self, url: &str) -> Option<(Uuid, String, String)> {
|
||||
let value = self.client.try_get_client().ok()?.parse_blob_url_v1(url)?;
|
||||
Some(value)
|
||||
}
|
||||
|
||||
async fn create_upload(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
file_id: &str,
|
||||
content_type: &str,
|
||||
|
@ -109,7 +110,7 @@ where
|
|||
|
||||
async fn upload_part(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
upload_id: &str,
|
||||
file_id: &str,
|
||||
|
@ -134,7 +135,7 @@ where
|
|||
|
||||
async fn complete_upload(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
upload_id: &str,
|
||||
file_id: &str,
|
||||
|
|
|
@ -58,12 +58,10 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
async fn open_workspace(&self, workspace_id: &str) -> Result<(), FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
async fn open_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
|
||||
let client = try_get_client?;
|
||||
let _ = client.open_workspace(&workspace_id).await?;
|
||||
let _ = client.open_workspace(workspace_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -88,11 +86,10 @@ where
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
async fn get_folder_data(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: &i64,
|
||||
) -> Result<Option<FolderData>, FlowyError> {
|
||||
let uid = *uid;
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
let params = QueryCollabParams {
|
||||
|
@ -111,10 +108,10 @@ where
|
|||
uid,
|
||||
CollabOrigin::Empty,
|
||||
DataSource::DocStateV1(doc_state),
|
||||
&workspace_id,
|
||||
&workspace_id.to_string(),
|
||||
vec![],
|
||||
)?;
|
||||
Ok(folder.get_folder_data(&workspace_id))
|
||||
Ok(folder.get_folder_data(&workspace_id.to_string()))
|
||||
}
|
||||
|
||||
async fn get_folder_snapshots(
|
||||
|
@ -128,18 +125,16 @@ where
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
async fn get_folder_doc_state(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
_uid: i64,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
collab_type: CollabType,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let object_id = object_id.to_string();
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
let params = QueryCollabParams {
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab::new(object_id, collab_type),
|
||||
inner: QueryCollab::new(object_id.clone(), collab_type),
|
||||
};
|
||||
let doc_state = try_get_client?
|
||||
.get_collab(params)
|
||||
|
@ -154,10 +149,9 @@ where
|
|||
|
||||
async fn full_sync_collab_object(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
params: FullSyncCollabParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
try_get_client?
|
||||
.collab_full_sync(
|
||||
|
@ -173,10 +167,9 @@ where
|
|||
|
||||
async fn batch_create_folder_collab_objects(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
objects: Vec<FolderCollabParams>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let params = objects
|
||||
.into_iter()
|
||||
|
@ -189,7 +182,7 @@ where
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
try_get_client?
|
||||
.create_collab_list(&workspace_id, params)
|
||||
.create_collab_list(workspace_id, params)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -200,10 +193,9 @@ where
|
|||
|
||||
async fn publish_view(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
payload: Vec<PublishPayload>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let params = payload
|
||||
.into_iter()
|
||||
|
@ -235,29 +227,20 @@ where
|
|||
|
||||
async fn unpublish_views(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
view_ids: Vec<String>,
|
||||
workspace_id: &Uuid,
|
||||
view_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let view_uuids = view_ids
|
||||
.iter()
|
||||
.map(|id| Uuid::parse_str(id).unwrap_or(Uuid::nil()))
|
||||
.collect::<Vec<_>>();
|
||||
try_get_client?
|
||||
.unpublish_collabs(&workspace_id, &view_uuids)
|
||||
.unpublish_collabs(&workspace_id, &view_ids)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_publish_info(&self, view_id: &str) -> Result<PublishInfo, FlowyError> {
|
||||
async fn get_publish_info(&self, view_id: &Uuid) -> Result<PublishInfo, FlowyError> {
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let view_id = Uuid::parse_str(view_id)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidParams, "Invalid view id"));
|
||||
|
||||
let view_id = view_id?;
|
||||
let info = try_get_client?
|
||||
.get_published_collab_info(&view_id)
|
||||
.get_published_collab_info(view_id)
|
||||
.await
|
||||
.map_err(FlowyError::from)?;
|
||||
Ok(info)
|
||||
|
@ -265,14 +248,11 @@ where
|
|||
|
||||
async fn set_publish_name(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
view_id: String,
|
||||
workspace_id: &Uuid,
|
||||
view_id: Uuid,
|
||||
new_name: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
let try_get_client = self.inner.try_get_client()?;
|
||||
let view_id = Uuid::parse_str(&view_id)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidParams, "Invalid view id"))?;
|
||||
|
||||
try_get_client
|
||||
.patch_published_collabs(
|
||||
workspace_id,
|
||||
|
@ -290,36 +270,33 @@ where
|
|||
|
||||
async fn set_publish_namespace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
new_namespace: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
try_get_client?
|
||||
.set_workspace_publish_namespace(&workspace_id, new_namespace)
|
||||
.set_workspace_publish_namespace(workspace_id, new_namespace)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_publish_namespace(&self, workspace_id: &str) -> Result<String, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
async fn get_publish_namespace(&self, workspace_id: &Uuid) -> Result<String, FlowyError> {
|
||||
let namespace = self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
.get_workspace_publish_namespace(&workspace_id)
|
||||
.get_workspace_publish_namespace(workspace_id)
|
||||
.await?;
|
||||
Ok(namespace)
|
||||
}
|
||||
|
||||
async fn list_published_views(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<PublishInfoView>, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let published_views = self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
.list_published_views(&workspace_id)
|
||||
.list_published_views(workspace_id)
|
||||
.await
|
||||
.map_err(FlowyError::from)?;
|
||||
Ok(published_views)
|
||||
|
@ -327,7 +304,7 @@ where
|
|||
|
||||
async fn get_default_published_view_info(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<PublishInfo, FlowyError> {
|
||||
let default_published_view_info = self
|
||||
.inner
|
||||
|
@ -340,7 +317,7 @@ where
|
|||
|
||||
async fn set_default_published_view(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
view_id: uuid::Uuid,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
|
@ -352,7 +329,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_default_published_view(&self, workspace_id: &str) -> Result<(), FlowyError> {
|
||||
async fn remove_default_published_view(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
self
|
||||
.inner
|
||||
.try_get_client()?
|
||||
|
|
|
@ -2,6 +2,7 @@ use client_api::entity::search_dto::SearchDocumentResponseItem;
|
|||
use flowy_error::FlowyError;
|
||||
use flowy_search_pub::cloud::SearchCloudService;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::af_cloud::AFServer;
|
||||
|
||||
|
@ -22,7 +23,7 @@ where
|
|||
{
|
||||
async fn document_search(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
query: String,
|
||||
) -> Result<Vec<SearchDocumentResponseItem>, FlowyError> {
|
||||
let client = self.inner.try_get_client()?;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
@ -189,9 +190,8 @@ where
|
|||
Ok(profile)
|
||||
}
|
||||
|
||||
async fn open_workspace(&self, workspace_id: &str) -> Result<UserWorkspace, FlowyError> {
|
||||
async fn open_workspace(&self, workspace_id: &Uuid) -> Result<UserWorkspace, FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let client = try_get_client?;
|
||||
let af_workspace = client.open_workspace(&workspace_id).await?;
|
||||
Ok(to_user_workspace(af_workspace))
|
||||
|
@ -222,17 +222,14 @@ where
|
|||
|
||||
async fn patch_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
new_workspace_name: Option<&str>,
|
||||
new_workspace_icon: Option<&str>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let owned_workspace_id = workspace_id.to_owned();
|
||||
let workspace_id = workspace_id.to_owned();
|
||||
let owned_workspace_name = new_workspace_name.map(|s| s.to_owned());
|
||||
let owned_workspace_icon = new_workspace_icon.map(|s| s.to_owned());
|
||||
let workspace_id: Uuid = owned_workspace_id
|
||||
.parse()
|
||||
.map_err(|_| ErrorCode::InvalidParams)?;
|
||||
let client = try_get_client?;
|
||||
client
|
||||
.patch_workspace(PatchWorkspaceParam {
|
||||
|
@ -244,18 +241,17 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_workspace(&self, workspace_id: &str) -> Result<(), FlowyError> {
|
||||
async fn delete_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let workspace_id_owned = workspace_id.to_owned();
|
||||
let client = try_get_client?;
|
||||
client.delete_workspace(&workspace_id_owned).await?;
|
||||
client.delete_workspace(workspace_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn invite_workspace_member(
|
||||
&self,
|
||||
invitee_email: String,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
role: Role,
|
||||
) -> Result<(), FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
|
@ -300,11 +296,11 @@ where
|
|||
async fn remove_workspace_member(
|
||||
&self,
|
||||
user_email: String,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<(), FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
try_get_client?
|
||||
.remove_workspace_members(workspace_id, vec![user_email])
|
||||
.remove_workspace_members(&workspace_id, vec![user_email])
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -312,20 +308,20 @@ where
|
|||
async fn update_workspace_member(
|
||||
&self,
|
||||
user_email: String,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
role: Role,
|
||||
) -> Result<(), FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let changeset = WorkspaceMemberChangeset::new(user_email).with_role(to_af_role(role));
|
||||
try_get_client?
|
||||
.update_workspace_member(workspace_id, changeset)
|
||||
.update_workspace_member(&workspace_id, changeset)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_workspace_members(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Vec<WorkspaceMember>, FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let members = try_get_client?
|
||||
|
@ -339,15 +335,12 @@ where
|
|||
|
||||
async fn get_workspace_member(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
uid: i64,
|
||||
) -> Result<WorkspaceMember, FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let client = try_get_client?;
|
||||
let query = QueryWorkspaceMember {
|
||||
workspace_id: workspace_id.clone(),
|
||||
uid,
|
||||
};
|
||||
let query = QueryWorkspaceMember { workspace_id, uid };
|
||||
let member = client.get_workspace_member(query).await?;
|
||||
Ok(from_af_workspace_member(member))
|
||||
}
|
||||
|
@ -355,17 +348,15 @@ where
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
async fn get_user_awareness_doc_state(
|
||||
&self,
|
||||
_uid: i64,
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
uid: i64,
|
||||
workspace_id: &Uuid,
|
||||
object_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let object_id = object_id.to_string();
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
let params = QueryCollabParams {
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab::new(object_id, CollabType::UserAwareness),
|
||||
inner: QueryCollab::new(object_id.clone(), CollabType::UserAwareness),
|
||||
};
|
||||
let resp = try_get_client?.get_collab(params).await?;
|
||||
check_request_workspace_id_is_match(&workspace_id, &cloned_user, "get user awareness object")?;
|
||||
|
@ -389,9 +380,12 @@ where
|
|||
let try_get_client = self.server.try_get_client();
|
||||
let collab_object = collab_object.clone();
|
||||
let client = try_get_client?;
|
||||
let workspace_id = Uuid::from_str(&collab_object.workspace_id)?;
|
||||
let object_id = Uuid::from_str(&collab_object.object_id)?;
|
||||
|
||||
let params = CreateCollabParams {
|
||||
workspace_id: collab_object.workspace_id,
|
||||
object_id: collab_object.object_id,
|
||||
workspace_id,
|
||||
object_id,
|
||||
collab_type: collab_object.collab_type,
|
||||
encoded_collab_v1: data,
|
||||
};
|
||||
|
@ -401,33 +395,35 @@ where
|
|||
|
||||
async fn batch_create_collab_object(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
objects: Vec<UserCollabParams>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let params = objects
|
||||
.into_iter()
|
||||
.map(|object| {
|
||||
CollabParams::new(
|
||||
object.object_id,
|
||||
u8::from(object.collab_type).into(),
|
||||
object.encoded_collab,
|
||||
)
|
||||
.flat_map(|object| {
|
||||
Uuid::from_str(&object.object_id)
|
||||
.and_then(|object_id| {
|
||||
Ok(CollabParams::new(
|
||||
object_id,
|
||||
u8::from(object.collab_type).into(),
|
||||
object.encoded_collab,
|
||||
))
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
try_get_client?
|
||||
.create_collab_list(&workspace_id, params)
|
||||
.create_collab_list(workspace_id, params)
|
||||
.await
|
||||
.map_err(FlowyError::from)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn leave_workspace(&self, workspace_id: &str) -> Result<(), FlowyError> {
|
||||
async fn leave_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let client = try_get_client?;
|
||||
client.leave_workspace(&workspace_id).await?;
|
||||
client.leave_workspace(workspace_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -454,14 +450,13 @@ where
|
|||
|
||||
async fn get_workspace_member_info(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
) -> Result<WorkspaceMember, FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let client = try_get_client?;
|
||||
let params = QueryWorkspaceMember {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
uid,
|
||||
};
|
||||
let member = client.get_workspace_member(params).await?;
|
||||
|
@ -518,12 +513,12 @@ where
|
|||
|
||||
async fn get_workspace_plan(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Vec<SubscriptionPlan>, FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let client = try_get_client?;
|
||||
let plans = client
|
||||
.get_active_workspace_subscriptions(&workspace_id)
|
||||
.get_active_workspace_subscriptions(&workspace_id.to_string())
|
||||
.await?;
|
||||
Ok(plans)
|
||||
}
|
||||
|
|
|
@ -2,21 +2,22 @@ use crate::af_cloud::define::ServerUser;
|
|||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use std::sync::Arc;
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// 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,
|
||||
expected_workspace_id: &Uuid,
|
||||
user: &Arc<dyn ServerUser>,
|
||||
action: impl AsRef<str>,
|
||||
) -> FlowyResult<()> {
|
||||
let actual_workspace_id = user.workspace_id()?;
|
||||
if expected_workspace_id != actual_workspace_id {
|
||||
if expected_workspace_id != &actual_workspace_id {
|
||||
warn!(
|
||||
"{}, expect workspace_id: {}, actual workspace_id: {}",
|
||||
action.as_ref(),
|
||||
expected_workspace_id,
|
||||
expected_workspace_id.to_string(),
|
||||
actual_workspace_id
|
||||
);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ use lib_infra::async_trait::async_trait;
|
|||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) struct DefaultChatCloudServiceImpl;
|
||||
|
||||
|
@ -16,104 +17,104 @@ pub(crate) struct DefaultChatCloudServiceImpl;
|
|||
impl ChatCloudService for DefaultChatCloudServiceImpl {
|
||||
async fn create_chat(
|
||||
&self,
|
||||
_uid: &i64,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_rag_ids: Vec<String>,
|
||||
uid: &i64,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn create_question(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_message: &str,
|
||||
_message_type: ChatMessageType,
|
||||
_metadata: &[ChatMessageMetadata],
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
message_type: ChatMessageType,
|
||||
metadata: &[ChatMessageMetadata],
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn create_answer(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_message: &str,
|
||||
_question_id: i64,
|
||||
_metadata: Option<serde_json::Value>,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message: &str,
|
||||
question_id: i64,
|
||||
metadata: Option<serde_json::Value>,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn stream_answer(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_message_id: i64,
|
||||
_format: ResponseFormat,
|
||||
_ai_model: Option<AIModel>,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
format: ResponseFormat,
|
||||
ai_model: Option<AIModel>,
|
||||
) -> Result<StreamAnswer, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn get_chat_messages(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_offset: MessageCursor,
|
||||
_limit: u64,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
offset: MessageCursor,
|
||||
limit: u64,
|
||||
) -> Result<RepeatedChatMessage, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn get_question_from_answer_id(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_answer_id: i64,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
answer_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn get_related_message(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_message_id: i64,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
) -> Result<RepeatedRelatedQuestion, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn get_answer(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_question_message_id: i64,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
question_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn stream_complete(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_params: CompleteTextParams,
|
||||
_ai_model: Option<AIModel>,
|
||||
workspace_id: &Uuid,
|
||||
params: CompleteTextParams,
|
||||
ai_model: Option<AIModel>,
|
||||
) -> Result<StreamComplete, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("complete text is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn embed_file(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_file_path: &Path,
|
||||
_chat_id: &str,
|
||||
_metadata: Option<HashMap<String, Value>>,
|
||||
workspace_id: &Uuid,
|
||||
file_path: &Path,
|
||||
chat_id: &Uuid,
|
||||
metadata: Option<HashMap<String, Value>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("indexing file is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn get_local_ai_config(&self, _workspace_id: &str) -> Result<LocalAIConfig, FlowyError> {
|
||||
async fn get_local_ai_config(&self, workspace_id: &Uuid) -> Result<LocalAIConfig, FlowyError> {
|
||||
Err(
|
||||
FlowyError::not_support()
|
||||
.with_context("Get local ai config is not supported in local server."),
|
||||
|
@ -122,7 +123,7 @@ impl ChatCloudService for DefaultChatCloudServiceImpl {
|
|||
|
||||
async fn get_workspace_plan(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<SubscriptionPlan>, FlowyError> {
|
||||
Err(
|
||||
FlowyError::not_support()
|
||||
|
@ -132,26 +133,26 @@ impl ChatCloudService for DefaultChatCloudServiceImpl {
|
|||
|
||||
async fn get_chat_settings(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<ChatSettings, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn update_chat_settings(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_chat_id: &str,
|
||||
_params: UpdateChatParams,
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
params: UpdateChatParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn get_available_models(&self, _workspace_id: &str) -> Result<ModelList, FlowyError> {
|
||||
async fn get_available_models(&self, workspace_id: &Uuid) -> Result<ModelList, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn get_workspace_default_model(&self, _workspace_id: &str) -> Result<String, FlowyError> {
|
||||
async fn get_workspace_default_model(&self, workspace_id: &Uuid) -> Result<String, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use collab_user::core::default_user_awareness_data;
|
|||
use flowy_database_pub::cloud::{DatabaseCloudService, DatabaseSnapshot, EncodeCollabByOid};
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) struct LocalServerDatabaseCloudServiceImpl();
|
||||
|
||||
|
@ -14,50 +15,51 @@ pub(crate) struct LocalServerDatabaseCloudServiceImpl();
|
|||
impl DatabaseCloudService for LocalServerDatabaseCloudServiceImpl {
|
||||
async fn get_database_encode_collab(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
_workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
let object_id = object_id.to_string();
|
||||
match collab_type {
|
||||
CollabType::Document => {
|
||||
let encode_collab = default_document_collab_data(object_id)?;
|
||||
let encode_collab = default_document_collab_data(&object_id)?;
|
||||
Ok(Some(encode_collab))
|
||||
},
|
||||
CollabType::Database => default_database_data(object_id)
|
||||
CollabType::Database => default_database_data(&object_id)
|
||||
.await
|
||||
.map(Some)
|
||||
.map_err(Into::into),
|
||||
CollabType::WorkspaceDatabase => Ok(Some(default_workspace_database_data(object_id))),
|
||||
CollabType::WorkspaceDatabase => Ok(Some(default_workspace_database_data(&object_id))),
|
||||
CollabType::Folder => Ok(None),
|
||||
CollabType::DatabaseRow => Ok(None),
|
||||
CollabType::UserAwareness => Ok(Some(default_user_awareness_data(object_id))),
|
||||
CollabType::UserAwareness => Ok(Some(default_user_awareness_data(&object_id))),
|
||||
CollabType::Unknown => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_database_encode_collab(
|
||||
&self,
|
||||
_object_id: &str,
|
||||
_collab_type: CollabType,
|
||||
_workspace_id: &str,
|
||||
_encoded_collab: EncodedCollab,
|
||||
object_id: &Uuid,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn batch_get_database_encode_collab(
|
||||
&self,
|
||||
_object_ids: Vec<String>,
|
||||
_object_ty: CollabType,
|
||||
_workspace_id: &str,
|
||||
object_ids: Vec<Uuid>,
|
||||
object_ty: CollabType,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<EncodeCollabByOid, FlowyError> {
|
||||
Ok(EncodeCollabByOid::default())
|
||||
}
|
||||
|
||||
async fn get_database_collab_object_snapshots(
|
||||
&self,
|
||||
_object_id: &str,
|
||||
_limit: usize,
|
||||
object_id: &Uuid,
|
||||
limit: usize,
|
||||
) -> Result<Vec<DatabaseSnapshot>, FlowyError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use collab::entity::EncodedCollab;
|
|||
use flowy_document_pub::cloud::*;
|
||||
use flowy_error::{ErrorCode, FlowyError};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) struct LocalServerDocumentCloudServiceImpl();
|
||||
|
||||
|
@ -9,8 +10,8 @@ pub(crate) struct LocalServerDocumentCloudServiceImpl();
|
|||
impl DocumentCloudService for LocalServerDocumentCloudServiceImpl {
|
||||
async fn get_document_doc_state(
|
||||
&self,
|
||||
document_id: &str,
|
||||
_workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let document_id = document_id.to_string();
|
||||
|
||||
|
@ -22,26 +23,26 @@ impl DocumentCloudService for LocalServerDocumentCloudServiceImpl {
|
|||
|
||||
async fn get_document_snapshots(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
_limit: usize,
|
||||
_workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
limit: usize,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<DocumentSnapshot>, FlowyError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
async fn get_document_data(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
_workspace_id: &str,
|
||||
document_id: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Option<DocumentData>, FlowyError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn create_document_collab(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_document_id: &str,
|
||||
_encoded_collab: EncodedCollab,
|
||||
workspace_id: &Uuid,
|
||||
document_id: &Uuid,
|
||||
encoded_collab: EncodedCollab,
|
||||
) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::local_server::LocalServerDB;
|
||||
use client_api::entity::workspace_dto::PublishInfoView;
|
||||
use client_api::entity::PublishInfo;
|
||||
use collab_entity::CollabType;
|
||||
|
||||
use crate::local_server::LocalServerDB;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_folder_pub::cloud::{
|
||||
gen_workspace_id, FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot,
|
||||
|
@ -12,6 +11,7 @@ use flowy_folder_pub::cloud::{
|
|||
};
|
||||
use flowy_folder_pub::entities::PublishPayload;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) struct LocalServerFolderCloudServiceImpl {
|
||||
#[allow(dead_code)]
|
||||
|
@ -29,7 +29,7 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
|||
))
|
||||
}
|
||||
|
||||
async fn open_workspace(&self, _workspace_id: &str) -> Result<(), FlowyError> {
|
||||
async fn open_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,8 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
|||
|
||||
async fn get_folder_data(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_uid: &i64,
|
||||
workspace_id: &Uuid,
|
||||
uid: &i64,
|
||||
) -> Result<Option<FolderData>, FlowyError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
@ -55,18 +55,18 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
|||
|
||||
async fn get_folder_doc_state(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_uid: i64,
|
||||
_collab_type: CollabType,
|
||||
_object_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
collab_type: CollabType,
|
||||
object_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn batch_create_folder_collab_objects(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_objects: Vec<FolderCollabParams>,
|
||||
workspace_id: &Uuid,
|
||||
objects: Vec<FolderCollabParams>,
|
||||
) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -77,68 +77,68 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
|||
|
||||
async fn publish_view(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_payload: Vec<PublishPayload>,
|
||||
workspace_id: &Uuid,
|
||||
payload: Vec<PublishPayload>,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn unpublish_views(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_view_ids: Vec<String>,
|
||||
workspace_id: &Uuid,
|
||||
view_ids: Vec<Uuid>,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn get_publish_info(&self, _view_id: &str) -> Result<PublishInfo, FlowyError> {
|
||||
async fn get_publish_info(&self, view_id: &Uuid) -> Result<PublishInfo, FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn set_publish_namespace(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_new_namespace: String,
|
||||
workspace_id: &Uuid,
|
||||
new_namespace: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn get_publish_namespace(&self, _workspace_id: &str) -> Result<String, FlowyError> {
|
||||
async fn get_publish_namespace(&self, workspace_id: &Uuid) -> Result<String, FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn set_publish_name(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_view_id: String,
|
||||
_new_name: String,
|
||||
workspace_id: &Uuid,
|
||||
view_id: Uuid,
|
||||
new_name: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn list_published_views(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<Vec<PublishInfoView>, FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn get_default_published_view_info(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
) -> Result<PublishInfo, FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn set_default_published_view(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_view_id: uuid::Uuid,
|
||||
workspace_id: &Uuid,
|
||||
view_id: uuid::Uuid,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
async fn remove_default_published_view(&self, _workspace_id: &str) -> Result<(), FlowyError> {
|
||||
async fn remove_default_published_view(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::local_version_not_support())
|
||||
}
|
||||
|
||||
|
@ -148,8 +148,8 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
|||
|
||||
async fn full_sync_collab_object(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_params: FullSyncCollabParams,
|
||||
workspace_id: &Uuid,
|
||||
params: FullSyncCollabParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||
}
|
||||
}
|
||||
|
||||
async fn open_workspace(&self, _workspace_id: &str) -> Result<UserWorkspace, FlowyError> {
|
||||
async fn open_workspace(&self, workspace_id: &Uuid) -> Result<UserWorkspace, FlowyError> {
|
||||
Err(
|
||||
FlowyError::local_version_not_support()
|
||||
.with_context("local server doesn't support open workspace"),
|
||||
|
@ -147,11 +147,16 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||
|
||||
async fn get_user_awareness_doc_state(
|
||||
&self,
|
||||
_uid: i64,
|
||||
_workspace_id: &str,
|
||||
object_id: &str,
|
||||
uid: i64,
|
||||
workspace_id: &Uuid,
|
||||
object_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError> {
|
||||
let collab = Collab::new_with_origin(CollabOrigin::Empty, object_id, vec![], false);
|
||||
let collab = Collab::new_with_origin(
|
||||
CollabOrigin::Empty,
|
||||
object_id.to_string().as_str(),
|
||||
vec![],
|
||||
false,
|
||||
);
|
||||
let awareness = UserAwareness::create(collab, None)?;
|
||||
let encode_collab = awareness.encode_collab_v1(|_collab| Ok::<_, FlowyError>(()))?;
|
||||
Ok(encode_collab.doc_state.to_vec())
|
||||
|
@ -171,8 +176,8 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||
|
||||
async fn batch_create_collab_object(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_objects: Vec<UserCollabParams>,
|
||||
workspace_id: &Uuid,
|
||||
objects: Vec<UserCollabParams>,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(
|
||||
FlowyError::local_version_not_support()
|
||||
|
@ -187,7 +192,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||
)
|
||||
}
|
||||
|
||||
async fn delete_workspace(&self, _workspace_id: &str) -> Result<(), FlowyError> {
|
||||
async fn delete_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
Err(
|
||||
FlowyError::local_version_not_support()
|
||||
.with_context("local server doesn't support multiple workspaces"),
|
||||
|
@ -196,9 +201,9 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||
|
||||
async fn patch_workspace(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_new_workspace_name: Option<&str>,
|
||||
_new_workspace_icon: Option<&str>,
|
||||
workspace_id: &Uuid,
|
||||
new_workspace_name: Option<&str>,
|
||||
new_workspace_icon: Option<&str>,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(
|
||||
FlowyError::local_version_not_support()
|
||||
|
|
|
@ -39,7 +39,7 @@ pub fn af_cloud_server(config: AFCloudConfiguration) -> Arc<AppFlowyCloudServer>
|
|||
|
||||
struct FakeServerUserImpl;
|
||||
impl ServerUser for FakeServerUserImpl {
|
||||
fn workspace_id(&self) -> FlowyResult<String> {
|
||||
fn workspace_id(&self) -> FlowyResult<Uuid> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
lib-infra.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
async-trait.workspace = true
|
||||
mime = "0.3.17"
|
||||
|
@ -17,4 +16,4 @@ mime_guess = "2.0.4"
|
|||
client-api-entity = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync", "io-util"] }
|
||||
anyhow = "1.0.86"
|
||||
tracing.workspace = true
|
||||
uuid.workspace = true
|
|
@ -3,6 +3,7 @@ use async_trait::async_trait;
|
|||
use bytes::Bytes;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use mime::Mime;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[async_trait]
|
||||
pub trait StorageCloudService: Send + Sync {
|
||||
|
@ -47,17 +48,17 @@ pub trait StorageCloudService: Send + Sync {
|
|||
async fn get_object(&self, url: String) -> Result<ObjectValue, FlowyError>;
|
||||
async fn get_object_url_v1(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
file_id: &str,
|
||||
) -> FlowyResult<String>;
|
||||
|
||||
/// Return workspace_id, parent_dir, file_id
|
||||
async fn parse_object_url_v1(&self, url: &str) -> Option<(String, String, String)>;
|
||||
async fn parse_object_url_v1(&self, url: &str) -> Option<(Uuid, String, String)>;
|
||||
|
||||
async fn create_upload(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
file_id: &str,
|
||||
content_type: &str,
|
||||
|
@ -66,7 +67,7 @@ pub trait StorageCloudService: Send + Sync {
|
|||
|
||||
async fn upload_part(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
upload_id: &str,
|
||||
file_id: &str,
|
||||
|
@ -76,7 +77,7 @@ pub trait StorageCloudService: Send + Sync {
|
|||
|
||||
async fn complete_upload(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
upload_id: &str,
|
||||
file_id: &str,
|
||||
|
@ -85,7 +86,7 @@ pub trait StorageCloudService: Send + Sync {
|
|||
}
|
||||
|
||||
pub struct ObjectIdentity {
|
||||
pub workspace_id: String,
|
||||
pub workspace_id: Uuid,
|
||||
pub file_id: String,
|
||||
pub ext: String,
|
||||
}
|
||||
|
@ -97,7 +98,7 @@ pub struct ObjectValue {
|
|||
}
|
||||
|
||||
pub struct StorageObject {
|
||||
pub workspace_id: String,
|
||||
pub workspace_id: Uuid,
|
||||
pub file_name: String,
|
||||
pub value: ObjectValueSupabase,
|
||||
}
|
||||
|
@ -126,9 +127,9 @@ impl StorageObject {
|
|||
/// * `name`: The name of the storage object.
|
||||
/// * `file_path`: The file path to the storage object's data.
|
||||
///
|
||||
pub fn from_file<T: ToString>(workspace_id: &str, file_name: &str, file_path: T) -> Self {
|
||||
pub fn from_file<T: ToString>(workspace_id: &Uuid, file_name: &str, file_path: T) -> Self {
|
||||
Self {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
workspace_id: *workspace_id,
|
||||
file_name: file_name.to_string(),
|
||||
value: ObjectValueSupabase::File {
|
||||
file_path: file_path.to_string(),
|
||||
|
@ -145,14 +146,14 @@ impl StorageObject {
|
|||
/// * `mime`: The MIME type of the storage object.
|
||||
///
|
||||
pub fn from_bytes<B: Into<Bytes>>(
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
file_name: &str,
|
||||
bytes: B,
|
||||
mime: String,
|
||||
) -> Self {
|
||||
let bytes = bytes.into();
|
||||
Self {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
workspace_id: *workspace_id,
|
||||
file_name: file_name.to_string(),
|
||||
value: ObjectValueSupabase::Bytes { bytes, mime },
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ tokio = { workspace = true, features = ["sync", "io-util"] }
|
|||
tracing.workspace = true
|
||||
flowy-sqlite.workspace = true
|
||||
mime_guess = "2.0.4"
|
||||
fxhash = "0.2.1"
|
||||
anyhow = "1.0.86"
|
||||
chrono = "0.4.33"
|
||||
flowy-notification = { workspace = true }
|
||||
flowy-derive.workspace = true
|
||||
|
@ -26,8 +24,8 @@ protobuf = { workspace = true }
|
|||
dashmap.workspace = true
|
||||
strum_macros = "0.25.2"
|
||||
allo-isolate = { version = "^0.1", features = ["catch-unwind"] }
|
||||
futures-util = "0.3.30"
|
||||
collab-importer = { workspace = true }
|
||||
uuid.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
|
|
|
@ -24,15 +24,17 @@ use lib_infra::box_any::BoxAny;
|
|||
use lib_infra::isolate_stream::{IsolateSink, SinkExt};
|
||||
use lib_infra::util::timestamp;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::sync::{broadcast, watch};
|
||||
use tracing::{debug, error, info, instrument, trace};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub trait StorageUserService: Send + Sync + 'static {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<Uuid, FlowyError>;
|
||||
fn sqlite_connection(&self, uid: i64) -> Result<DBConnection, FlowyError>;
|
||||
fn get_application_root_dir(&self) -> &str;
|
||||
}
|
||||
|
@ -157,7 +159,8 @@ impl StorageManager {
|
|||
|
||||
let uid = self.user_service.user_id().ok()?;
|
||||
let mut conn = self.user_service.sqlite_connection(uid).ok()?;
|
||||
let is_finish = is_upload_completed(&mut conn, &workspace_id, &parent_dir, &file_id).ok()?;
|
||||
let is_finish =
|
||||
is_upload_completed(&mut conn, &workspace_id.to_string(), &parent_dir, &file_id).ok()?;
|
||||
|
||||
if let Err(err) = self.global_notifier.send(FileProgress::new_progress(
|
||||
url.to_string(),
|
||||
|
@ -229,7 +232,7 @@ async fn prepare_upload_task(
|
|||
if let Ok(uid) = user_service.user_id() {
|
||||
let workspace_id = user_service.workspace_id()?;
|
||||
let conn = user_service.sqlite_connection(uid)?;
|
||||
let upload_files = batch_select_upload_file(conn, &workspace_id, 100, false)?;
|
||||
let upload_files = batch_select_upload_file(conn, &workspace_id.to_string(), 100, false)?;
|
||||
let tasks = upload_files
|
||||
.into_iter()
|
||||
.map(|upload_file| UploadTask::BackgroundTask {
|
||||
|
@ -269,7 +272,7 @@ impl StorageService for StorageServiceImpl {
|
|||
|
||||
self
|
||||
.task_queue
|
||||
.remove_task(&workspace_id, &parent_dir, &file_id)
|
||||
.remove_task(&workspace_id.to_string(), &parent_dir, &file_id)
|
||||
.await;
|
||||
|
||||
trace!("[File] delete progress notifier: {}", file_id);
|
||||
|
@ -278,7 +281,7 @@ impl StorageService for StorageServiceImpl {
|
|||
self
|
||||
.user_service
|
||||
.sqlite_connection(self.user_service.user_id()?)?,
|
||||
&workspace_id,
|
||||
&workspace_id.to_string(),
|
||||
&parent_dir,
|
||||
&file_id,
|
||||
) {
|
||||
|
@ -384,9 +387,10 @@ impl StorageService for StorageServiceImpl {
|
|||
let conn = self
|
||||
.user_service
|
||||
.sqlite_connection(self.user_service.user_id()?)?;
|
||||
let workspace_id = Uuid::from_str(&record.workspace_id)?;
|
||||
let url = self
|
||||
.cloud_service
|
||||
.get_object_url_v1(&record.workspace_id, &record.parent_dir, &record.file_id)
|
||||
.get_object_url_v1(&workspace_id, &record.parent_dir, &record.file_id)
|
||||
.await?;
|
||||
let file_id = record.file_id.clone();
|
||||
match insert_upload_file(conn, &record) {
|
||||
|
@ -478,7 +482,8 @@ impl StorageService for StorageServiceImpl {
|
|||
.user_service
|
||||
.sqlite_connection(self.user_service.user_id()?)?;
|
||||
let workspace_id = self.user_service.workspace_id()?;
|
||||
is_upload_completed(&mut conn, &workspace_id, parent_idr, file_id).unwrap_or(false)
|
||||
is_upload_completed(&mut conn, &workspace_id.to_string(), parent_idr, file_id)
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
||||
if is_completed {
|
||||
|
@ -590,9 +595,10 @@ async fn start_upload(
|
|||
upload_file.file_id
|
||||
);
|
||||
|
||||
let workspace_id = Uuid::from_str(&upload_file.workspace_id)?;
|
||||
let create_upload_resp_result = cloud_service
|
||||
.create_upload(
|
||||
&upload_file.workspace_id,
|
||||
&workspace_id,
|
||||
&upload_file.parent_dir,
|
||||
&upload_file.file_id,
|
||||
&upload_file.content_type,
|
||||
|
@ -601,11 +607,7 @@ async fn start_upload(
|
|||
.await;
|
||||
|
||||
let file_url = cloud_service
|
||||
.get_object_url_v1(
|
||||
&upload_file.workspace_id,
|
||||
&upload_file.parent_dir,
|
||||
&upload_file.file_id,
|
||||
)
|
||||
.get_object_url_v1(&workspace_id, &upload_file.parent_dir, &upload_file.file_id)
|
||||
.await?;
|
||||
|
||||
if let Err(err) = create_upload_resp_result.as_ref() {
|
||||
|
@ -653,7 +655,7 @@ async fn start_upload(
|
|||
match upload_part(
|
||||
cloud_service,
|
||||
user_service,
|
||||
&upload_file.workspace_id,
|
||||
&workspace_id,
|
||||
&upload_file.parent_dir,
|
||||
&upload_file.upload_id,
|
||||
&upload_file.file_id,
|
||||
|
@ -782,7 +784,7 @@ async fn resume_upload(
|
|||
async fn upload_part(
|
||||
cloud_service: &Arc<dyn StorageCloudService>,
|
||||
user_service: &Arc<dyn StorageUserService>,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
parent_dir: &str,
|
||||
upload_id: &str,
|
||||
file_id: &str,
|
||||
|
@ -822,12 +824,9 @@ async fn complete_upload(
|
|||
parts: Vec<CompletedPartRequest>,
|
||||
global_notifier: &GlobalNotifier,
|
||||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = Uuid::from_str(&upload_file.workspace_id)?;
|
||||
let file_url = cloud_service
|
||||
.get_object_url_v1(
|
||||
&upload_file.workspace_id,
|
||||
&upload_file.parent_dir,
|
||||
&upload_file.file_id,
|
||||
)
|
||||
.get_object_url_v1(&workspace_id, &upload_file.parent_dir, &upload_file.file_id)
|
||||
.await?;
|
||||
|
||||
info!(
|
||||
|
@ -838,7 +837,7 @@ async fn complete_upload(
|
|||
);
|
||||
match cloud_service
|
||||
.complete_upload(
|
||||
&upload_file.workspace_id,
|
||||
&workspace_id,
|
||||
&upload_file.parent_dir,
|
||||
&upload_file.upload_id,
|
||||
&upload_file.file_id,
|
||||
|
|
|
@ -171,7 +171,7 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
/// return None if the user is not found
|
||||
async fn get_user_profile(&self, credential: UserCredentials) -> Result<UserProfile, FlowyError>;
|
||||
|
||||
async fn open_workspace(&self, workspace_id: &str) -> Result<UserWorkspace, FlowyError>;
|
||||
async fn open_workspace(&self, workspace_id: &Uuid) -> Result<UserWorkspace, FlowyError>;
|
||||
|
||||
/// Return the all the workspaces of the user
|
||||
async fn get_all_workspace(&self, uid: i64) -> Result<Vec<UserWorkspace>, FlowyError>;
|
||||
|
@ -183,18 +183,18 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
// Updates the workspace name and icon
|
||||
async fn patch_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
new_workspace_name: Option<&str>,
|
||||
new_workspace_icon: Option<&str>,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
/// Deletes a workspace owned by the user.
|
||||
async fn delete_workspace(&self, workspace_id: &str) -> Result<(), FlowyError>;
|
||||
async fn delete_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError>;
|
||||
|
||||
async fn invite_workspace_member(
|
||||
&self,
|
||||
invitee_email: String,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
role: Role,
|
||||
) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
|
@ -214,7 +214,7 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
async fn remove_workspace_member(
|
||||
&self,
|
||||
user_email: String,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
async fn update_workspace_member(
|
||||
&self,
|
||||
user_email: String,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
role: Role,
|
||||
) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
|
@ -230,14 +230,14 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn get_workspace_members(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Vec<WorkspaceMember>, FlowyError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
async fn get_workspace_member(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
uid: i64,
|
||||
) -> Result<WorkspaceMember, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
|
@ -246,8 +246,8 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
async fn get_user_awareness_doc_state(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
object_id: &Uuid,
|
||||
) -> Result<Vec<u8>, FlowyError>;
|
||||
|
||||
fn receive_realtime_event(&self, _json: Value) {}
|
||||
|
@ -266,11 +266,11 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn batch_create_collab_object(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
objects: Vec<UserCollabParams>,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn leave_workspace(&self, workspace_id: &str) -> Result<(), FlowyError> {
|
||||
async fn leave_workspace(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,7 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn get_workspace_member_info(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
) -> Result<WorkspaceMember, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
|
@ -318,7 +318,7 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||
|
||||
async fn get_workspace_plan(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Vec<SubscriptionPlan>, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::str::FromStr;
|
|||
use chrono::{DateTime, Utc};
|
||||
pub use client_api::entity::billing_dto::RecurringInterval;
|
||||
use client_api::entity::AFRole;
|
||||
use flowy_error::FlowyResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use serde_repr::*;
|
||||
|
@ -151,6 +152,11 @@ pub struct UserWorkspace {
|
|||
}
|
||||
|
||||
impl UserWorkspace {
|
||||
pub fn workspace_id(&self) -> FlowyResult<Uuid> {
|
||||
let id = Uuid::from_str(&self.id)?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn new_local(workspace_id: &str, _uid: i64) -> Self {
|
||||
Self {
|
||||
id: workspace_id.to_string(),
|
||||
|
|
|
@ -3,6 +3,7 @@ use flowy_error::FlowyResult;
|
|||
use flowy_folder_pub::entities::ImportFrom;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserWorkspaceService: Send + Sync {
|
||||
|
@ -19,5 +20,5 @@ pub trait UserWorkspaceService: Send + Sync {
|
|||
) -> FlowyResult<()>;
|
||||
|
||||
/// Removes local indexes when a workspace is left/deleted
|
||||
fn did_delete_workspace(&self, workspace_id: String) -> FlowyResult<()>;
|
||||
fn did_delete_workspace(&self, workspace_id: &Uuid) -> FlowyResult<()>;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@ use flowy_user_pub::entities::*;
|
|||
use lib_dispatch::prelude::*;
|
||||
use lib_infra::box_any::BoxAny;
|
||||
use serde_json::Value;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Weak;
|
||||
use std::{convert::TryInto, sync::Arc};
|
||||
use tracing::{event, trace};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::notification::{send_notification, UserNotification};
|
||||
|
@ -515,7 +517,8 @@ pub async fn open_workspace_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params = data.try_into_inner()?;
|
||||
manager.open_workspace(¶ms.workspace_id).await?;
|
||||
let workspace_id = Uuid::from_str(¶ms.workspace_id)?;
|
||||
manager.open_workspace(&workspace_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -645,8 +648,9 @@ pub async fn delete_workspace_member_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let data = data.try_into_inner()?;
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let workspace_id = Uuid::from_str(&data.workspace_id)?;
|
||||
manager
|
||||
.remove_workspace_member(data.email, data.workspace_id)
|
||||
.remove_workspace_member(data.email, workspace_id)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -658,8 +662,9 @@ pub async fn get_workspace_members_handler(
|
|||
) -> DataResult<RepeatedWorkspaceMemberPB, FlowyError> {
|
||||
let data = data.try_into_inner()?;
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let workspace_id = Uuid::from_str(&data.workspace_id)?;
|
||||
let members = manager
|
||||
.get_workspace_members(data.workspace_id)
|
||||
.get_workspace_members(workspace_id)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(WorkspaceMemberPB::from)
|
||||
|
@ -674,8 +679,9 @@ pub async fn update_workspace_member_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let data = data.try_into_inner()?;
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let workspace_id = Uuid::from_str(&data.workspace_id)?;
|
||||
manager
|
||||
.update_workspace_member(data.email, data.workspace_id, data.role.into())
|
||||
.update_workspace_member(data.email, workspace_id, data.role.into())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -698,6 +704,7 @@ pub async fn delete_workspace_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = delete_workspace_param.try_into_inner()?.workspace_id;
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let workspace_id = Uuid::from_str(&workspace_id)?;
|
||||
manager.delete_workspace(&workspace_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -709,8 +716,9 @@ pub async fn rename_workspace_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let params = rename_workspace_param.try_into_inner()?;
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let workspace_id = Uuid::from_str(¶ms.workspace_id)?;
|
||||
manager
|
||||
.patch_workspace(¶ms.workspace_id, Some(¶ms.new_name), None)
|
||||
.patch_workspace(&workspace_id, Some(¶ms.new_name), None)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -722,8 +730,9 @@ pub async fn change_workspace_icon_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let params = change_workspace_icon_param.try_into_inner()?;
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let workspace_id = Uuid::from_str(¶ms.workspace_id)?;
|
||||
manager
|
||||
.patch_workspace(¶ms.workspace_id, None, Some(¶ms.new_icon))
|
||||
.patch_workspace(&workspace_id, None, Some(¶ms.new_icon))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -735,8 +744,9 @@ pub async fn invite_workspace_member_handler(
|
|||
) -> Result<(), FlowyError> {
|
||||
let param = param.try_into_inner()?;
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let workspace_id = Uuid::from_str(¶m.workspace_id)?;
|
||||
manager
|
||||
.invite_member_to_workspace(param.workspace_id, param.invitee_email, param.role.into())
|
||||
.invite_member_to_workspace(workspace_id, param.invitee_email, param.role.into())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -772,6 +782,7 @@ pub async fn leave_workspace_handler(
|
|||
manager: AFPluginState<Weak<UserManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let workspace_id = param.into_inner().workspace_id;
|
||||
let workspace_id = Uuid::from_str(&workspace_id)?;
|
||||
let manager = upgrade_manager(manager)?;
|
||||
manager.leave_workspace(&workspace_id).await?;
|
||||
Ok(())
|
||||
|
|
|
@ -13,8 +13,10 @@ use flowy_sqlite::DBConnection;
|
|||
use flowy_user_pub::entities::UserWorkspace;
|
||||
use flowy_user_pub::session::Session;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{error, info};
|
||||
use uuid::Uuid;
|
||||
|
||||
const SQLITE_VACUUM_042: &str = "sqlite_vacuum_042_version";
|
||||
|
||||
|
@ -68,14 +70,16 @@ impl AuthenticateUser {
|
|||
Ok(self.user_config.device_id.to_string())
|
||||
}
|
||||
|
||||
pub fn workspace_id(&self) -> FlowyResult<String> {
|
||||
pub fn workspace_id(&self) -> FlowyResult<Uuid> {
|
||||
let session = self.get_session()?;
|
||||
Ok(session.user_workspace.id.clone())
|
||||
let workspace_uuid = Uuid::from_str(&session.user_workspace.id)?;
|
||||
Ok(workspace_uuid)
|
||||
}
|
||||
|
||||
pub fn workspace_database_object_id(&self) -> FlowyResult<String> {
|
||||
pub fn workspace_database_object_id(&self) -> FlowyResult<Uuid> {
|
||||
let session = self.get_session()?;
|
||||
Ok(session.user_workspace.workspace_database_id.clone())
|
||||
let id = Uuid::from_str(&session.user_workspace.workspace_database_id)?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn get_collab_db(&self, uid: i64) -> FlowyResult<Weak<CollabKVDB>> {
|
||||
|
|
|
@ -4,6 +4,7 @@ use flowy_error::{FlowyError, FlowyResult};
|
|||
use flowy_user_pub::cloud::UserCloudServiceProvider;
|
||||
use std::sync::Weak;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// `PeriodicallyCheckBillingState` is designed to periodically verify the subscription
|
||||
/// plan of a given workspace. It utilizes a cloud service provider to fetch the current
|
||||
|
@ -13,7 +14,7 @@ use std::time::Duration;
|
|||
/// at specified intervals until the expected plan is found or the maximum number of
|
||||
/// attempts is reached.
|
||||
pub struct PeriodicallyCheckBillingState {
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
cloud_service: Weak<dyn UserCloudServiceProvider>,
|
||||
expected_plan: Option<SubscriptionPlan>,
|
||||
user: Weak<AuthenticateUser>,
|
||||
|
@ -21,7 +22,7 @@ pub struct PeriodicallyCheckBillingState {
|
|||
|
||||
impl PeriodicallyCheckBillingState {
|
||||
pub fn new(
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
expected_plan: Option<SubscriptionPlan>,
|
||||
cloud_service: Weak<dyn UserCloudServiceProvider>,
|
||||
user: Weak<AuthenticateUser>,
|
||||
|
|
|
@ -43,6 +43,8 @@ use std::ops::{Deref, DerefMut};
|
|||
use std::path::Path;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{error, event, info, instrument, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) struct ImportedFolder {
|
||||
pub imported_session: Session,
|
||||
pub imported_collab_db: Arc<CollabKVDB>,
|
||||
|
@ -1172,7 +1174,7 @@ impl DerefMut for OldToNewIdMap {
|
|||
pub async fn upload_collab_objects_data(
|
||||
uid: i64,
|
||||
user_collab_db: Weak<CollabKVDB>,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
user_authenticator: &Authenticator,
|
||||
collab_data: ImportedCollabData,
|
||||
user_cloud_service: Arc<dyn UserCloudService>,
|
||||
|
@ -1275,7 +1277,7 @@ pub async fn upload_collab_objects_data(
|
|||
|
||||
async fn batch_create(
|
||||
uid: i64,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
user_cloud_service: &Arc<dyn UserCloudService>,
|
||||
size_counter: &usize,
|
||||
objects: Vec<UserCollabParams>,
|
||||
|
|
|
@ -14,6 +14,7 @@ use flowy_sqlite::{query_dsl::*, DBConnection, ExpressionMethods};
|
|||
use flowy_user_pub::cloud::{UserCloudServiceProvider, UserUpdate};
|
||||
use flowy_user_pub::entities::*;
|
||||
use flowy_user_pub::workspace_service::UserWorkspaceService;
|
||||
use lib_infra::box_any::BoxAny;
|
||||
use semver::Version;
|
||||
use serde_json::Value;
|
||||
use std::string::ToString;
|
||||
|
@ -22,8 +23,7 @@ use std::sync::{Arc, Weak};
|
|||
use tokio::sync::Mutex;
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::{debug, error, event, info, instrument, warn};
|
||||
|
||||
use lib_infra::box_any::BoxAny;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::entities::{AuthStateChangedPB, AuthStatePB, UserProfilePB, UserSettingPB};
|
||||
use crate::event_map::{DefaultUserStatusCallback, UserStatusCallback};
|
||||
|
@ -58,7 +58,7 @@ pub struct UserManager {
|
|||
auth_process: Mutex<Option<UserAuthProcess>>,
|
||||
pub(crate) authenticate_user: Arc<AuthenticateUser>,
|
||||
refresh_user_profile_since: AtomicI64,
|
||||
pub(crate) is_loading_awareness: Arc<DashMap<String, bool>>,
|
||||
pub(crate) is_loading_awareness: Arc<DashMap<Uuid, bool>>,
|
||||
}
|
||||
|
||||
impl UserManager {
|
||||
|
|
|
@ -8,13 +8,13 @@ use collab_entity::CollabType;
|
|||
use collab_integrate::collab_builder::{
|
||||
AppFlowyCollabBuilder, CollabBuilderConfig, CollabPersistenceImpl,
|
||||
};
|
||||
use collab_integrate::CollabKVDB;
|
||||
use collab_user::core::{UserAwareness, UserAwarenessNotifier};
|
||||
use dashmap::try_result::TryResult;
|
||||
use tracing::{error, info, instrument, trace};
|
||||
|
||||
use collab_integrate::CollabKVDB;
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_user_pub::entities::{user_awareness_object_id, Authenticator};
|
||||
use tracing::{error, info, instrument, trace};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::entities::ReminderPB;
|
||||
use crate::user_manager::UserManager;
|
||||
|
@ -122,8 +122,7 @@ impl UserManager {
|
|||
authenticator: &Authenticator,
|
||||
) -> FlowyResult<()> {
|
||||
let authenticator = authenticator.clone();
|
||||
let object_id =
|
||||
user_awareness_object_id(&session.user_uuid, &session.user_workspace.id).to_string();
|
||||
let object_id = user_awareness_object_id(&session.user_uuid, &session.user_workspace.id);
|
||||
|
||||
// Try to acquire mutable access to `is_loading_awareness`.
|
||||
// Thread-safety is ensured by DashMap
|
||||
|
@ -156,7 +155,7 @@ impl UserManager {
|
|||
|
||||
let is_exist_on_disk = self
|
||||
.authenticate_user
|
||||
.is_collab_on_disk(session.user_id, &object_id)?;
|
||||
.is_collab_on_disk(session.user_id, &object_id.to_string())?;
|
||||
if authenticator.is_local() || is_exist_on_disk {
|
||||
trace!(
|
||||
"Initializing new user awareness from disk:{}, {:?}",
|
||||
|
@ -164,15 +163,13 @@ impl UserManager {
|
|||
authenticator
|
||||
);
|
||||
let collab_db = self.get_collab_db(session.user_id)?;
|
||||
let doc_state = CollabPersistenceImpl::new(
|
||||
collab_db.clone(),
|
||||
session.user_id,
|
||||
session.user_workspace.id.clone(),
|
||||
)
|
||||
.into_data_source();
|
||||
let workspace_id = session.user_workspace.workspace_id()?;
|
||||
let doc_state =
|
||||
CollabPersistenceImpl::new(collab_db.clone(), session.user_id, workspace_id)
|
||||
.into_data_source();
|
||||
let awareness = Self::collab_for_user_awareness(
|
||||
&self.collab_builder.clone(),
|
||||
&session.user_workspace.id,
|
||||
&workspace_id,
|
||||
session.user_id,
|
||||
&object_id,
|
||||
collab_db,
|
||||
|
@ -211,7 +208,7 @@ impl UserManager {
|
|||
fn load_awareness_from_server(
|
||||
&self,
|
||||
session: &Session,
|
||||
object_id: String,
|
||||
object_id: Uuid,
|
||||
authenticator: Authenticator,
|
||||
) -> FlowyResult<()> {
|
||||
// Clone necessary data
|
||||
|
@ -231,16 +228,14 @@ impl UserManager {
|
|||
}
|
||||
};
|
||||
|
||||
let workspace_id = session.user_workspace.workspace_id()?;
|
||||
let create_awareness = if authenticator.is_local() {
|
||||
let doc_state = CollabPersistenceImpl::new(
|
||||
collab_db.clone(),
|
||||
session.user_id,
|
||||
session.user_workspace.id.clone(),
|
||||
)
|
||||
.into_data_source();
|
||||
let doc_state =
|
||||
CollabPersistenceImpl::new(collab_db.clone(), session.user_id, workspace_id.clone())
|
||||
.into_data_source();
|
||||
Self::collab_for_user_awareness(
|
||||
&weak_builder,
|
||||
&session.user_workspace.id,
|
||||
&workspace_id,
|
||||
session.user_id,
|
||||
&object_id,
|
||||
collab_db,
|
||||
|
@ -251,7 +246,7 @@ impl UserManager {
|
|||
} else {
|
||||
let result = cloud_services
|
||||
.get_user_service()?
|
||||
.get_user_awareness_doc_state(session.user_id, &session.user_workspace.id, &object_id)
|
||||
.get_user_awareness_doc_state(session.user_id, &workspace_id, &object_id)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
|
@ -259,7 +254,7 @@ impl UserManager {
|
|||
trace!("Fetched user awareness collab from remote: {}", data.len());
|
||||
Self::collab_for_user_awareness(
|
||||
&weak_builder,
|
||||
&session.user_workspace.id,
|
||||
&workspace_id,
|
||||
session.user_id,
|
||||
&object_id,
|
||||
collab_db,
|
||||
|
@ -274,12 +269,12 @@ impl UserManager {
|
|||
let doc_state = CollabPersistenceImpl::new(
|
||||
collab_db.clone(),
|
||||
session.user_id,
|
||||
session.user_workspace.id.clone(),
|
||||
workspace_id.clone(),
|
||||
)
|
||||
.into_data_source();
|
||||
Self::collab_for_user_awareness(
|
||||
&weak_builder,
|
||||
&session.user_workspace.id,
|
||||
&workspace_id,
|
||||
session.user_id,
|
||||
&object_id,
|
||||
collab_db,
|
||||
|
@ -329,9 +324,9 @@ impl UserManager {
|
|||
/// user awareness.
|
||||
async fn collab_for_user_awareness(
|
||||
collab_builder: &Weak<AppFlowyCollabBuilder>,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
object_id: &Uuid,
|
||||
collab_db: Weak<CollabKVDB>,
|
||||
doc_state: DataSource,
|
||||
notifier: Option<UserAwarenessNotifier>,
|
||||
|
@ -375,8 +370,7 @@ impl UserManager {
|
|||
info!("User awareness is not loaded when trying to access it");
|
||||
|
||||
let session = self.get_session()?;
|
||||
let object_id =
|
||||
user_awareness_object_id(&session.user_uuid, &session.user_workspace.id).to_string();
|
||||
let object_id = user_awareness_object_id(&session.user_uuid, &session.user_workspace.id);
|
||||
let is_loading = self
|
||||
.is_loading_awareness
|
||||
.get(&object_id)
|
||||
|
|
|
@ -3,12 +3,11 @@ use client_api::entity::billing_dto::{RecurringInterval, SubscriptionPlanDetail}
|
|||
use client_api::entity::billing_dto::{SubscriptionPlan, WorkspaceUsageAndLimit};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_entity::{CollabObject, CollabType};
|
||||
use collab_integrate::CollabKVDB;
|
||||
use tracing::{error, info, instrument, trace, warn};
|
||||
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_folder_pub::entities::{ImportFrom, ImportedCollabData, ImportedFolderData};
|
||||
use flowy_sqlite::schema::user_workspace_table;
|
||||
|
@ -17,6 +16,8 @@ use flowy_user_pub::entities::{
|
|||
Role, UpdateUserProfileParams, UserWorkspace, WorkspaceInvitation, WorkspaceInvitationStatus,
|
||||
WorkspaceMember,
|
||||
};
|
||||
use tracing::{error, info, instrument, trace, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::entities::{
|
||||
RepeatedUserWorkspacePB, ResetWorkspacePB, SubscribeWorkspacePB, SuccessWorkspaceSubscriptionPB,
|
||||
|
@ -123,7 +124,7 @@ impl UserManager {
|
|||
match upload_collab_objects_data(
|
||||
user_id,
|
||||
weak_user_collab_db,
|
||||
¤t_session.user_workspace.id,
|
||||
¤t_session.user_workspace.workspace_id()?,
|
||||
&user.authenticator,
|
||||
collab_data,
|
||||
weak_user_cloud_service,
|
||||
|
@ -161,7 +162,7 @@ impl UserManager {
|
|||
}
|
||||
|
||||
#[instrument(skip(self), err)]
|
||||
pub async fn open_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
|
||||
pub async fn open_workspace(&self, workspace_id: &Uuid) -> FlowyResult<()> {
|
||||
info!("open workspace: {}", workspace_id);
|
||||
let user_workspace = self
|
||||
.cloud_services
|
||||
|
@ -221,7 +222,7 @@ impl UserManager {
|
|||
|
||||
pub async fn patch_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
new_workspace_name: Option<&str>,
|
||||
new_workspace_icon: Option<&str>,
|
||||
) -> FlowyResult<()> {
|
||||
|
@ -262,7 +263,7 @@ impl UserManager {
|
|||
}
|
||||
|
||||
#[instrument(level = "info", skip(self), err)]
|
||||
pub async fn leave_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
|
||||
pub async fn leave_workspace(&self, workspace_id: &Uuid) -> FlowyResult<()> {
|
||||
info!("leave workspace: {}", workspace_id);
|
||||
self
|
||||
.cloud_services
|
||||
|
@ -273,15 +274,15 @@ impl UserManager {
|
|||
// delete workspace from local sqlite db
|
||||
let uid = self.user_id()?;
|
||||
let conn = self.db_connection(uid)?;
|
||||
delete_user_workspaces(conn, workspace_id)?;
|
||||
delete_user_workspaces(conn, workspace_id.to_string().as_str())?;
|
||||
|
||||
self
|
||||
.user_workspace_service
|
||||
.did_delete_workspace(workspace_id.to_string())
|
||||
.did_delete_workspace(workspace_id)
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip(self), err)]
|
||||
pub async fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
|
||||
pub async fn delete_workspace(&self, workspace_id: &Uuid) -> FlowyResult<()> {
|
||||
info!("delete workspace: {}", workspace_id);
|
||||
self
|
||||
.cloud_services
|
||||
|
@ -290,18 +291,18 @@ impl UserManager {
|
|||
.await?;
|
||||
let uid = self.user_id()?;
|
||||
let conn = self.db_connection(uid)?;
|
||||
delete_user_workspaces(conn, workspace_id)?;
|
||||
delete_user_workspaces(conn, workspace_id.to_string().as_str())?;
|
||||
|
||||
self
|
||||
.user_workspace_service
|
||||
.did_delete_workspace(workspace_id.to_string())?;
|
||||
.did_delete_workspace(workspace_id)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn invite_member_to_workspace(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
invitee_email: String,
|
||||
role: Role,
|
||||
) -> FlowyResult<()> {
|
||||
|
@ -335,7 +336,7 @@ impl UserManager {
|
|||
pub async fn remove_workspace_member(
|
||||
&self,
|
||||
user_email: String,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) -> FlowyResult<()> {
|
||||
self
|
||||
.cloud_services
|
||||
|
@ -347,7 +348,7 @@ impl UserManager {
|
|||
|
||||
pub async fn get_workspace_members(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
) -> FlowyResult<Vec<WorkspaceMember>> {
|
||||
let members = self
|
||||
.cloud_services
|
||||
|
@ -359,7 +360,7 @@ impl UserManager {
|
|||
|
||||
pub async fn get_workspace_member(
|
||||
&self,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
uid: i64,
|
||||
) -> FlowyResult<WorkspaceMember> {
|
||||
let member = self
|
||||
|
@ -373,7 +374,7 @@ impl UserManager {
|
|||
pub async fn update_workspace_member(
|
||||
&self,
|
||||
user_email: String,
|
||||
workspace_id: String,
|
||||
workspace_id: Uuid,
|
||||
role: Role,
|
||||
) -> FlowyResult<()> {
|
||||
self
|
||||
|
@ -384,9 +385,9 @@ impl UserManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_user_workspace(&self, uid: i64, workspace_id: &str) -> Option<UserWorkspace> {
|
||||
pub fn get_user_workspace(&self, uid: i64, workspace_id: &Uuid) -> Option<UserWorkspace> {
|
||||
let conn = self.db_connection(uid).ok()?;
|
||||
get_user_workspace_op(workspace_id, conn)
|
||||
get_user_workspace_op(workspace_id.to_string().as_str(), conn)
|
||||
}
|
||||
|
||||
pub async fn get_all_user_workspaces(&self, uid: i64) -> FlowyResult<Vec<UserWorkspace>> {
|
||||
|
@ -581,10 +582,10 @@ impl UserManager {
|
|||
}
|
||||
|
||||
pub async fn get_workspace_member_info(&self, uid: i64) -> FlowyResult<WorkspaceMember> {
|
||||
let workspace_id = self.get_session()?.user_workspace.id.clone();
|
||||
let workspace_id = self.get_session()?.user_workspace.workspace_id()?;
|
||||
let db = self.authenticate_user.get_sqlite_connection(uid)?;
|
||||
// Can opt in using memory cache
|
||||
if let Ok(member_record) = select_workspace_member(db, &workspace_id, uid) {
|
||||
if let Ok(member_record) = select_workspace_member(db, &workspace_id.to_string(), uid) {
|
||||
if is_older_than_n_minutes(member_record.updated_at, 10) {
|
||||
self
|
||||
.get_workspace_member_info_from_remote(&workspace_id, uid)
|
||||
|
@ -608,7 +609,7 @@ impl UserManager {
|
|||
|
||||
async fn get_workspace_member_info_from_remote(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
workspace_id: &Uuid,
|
||||
uid: i64,
|
||||
) -> FlowyResult<WorkspaceMember> {
|
||||
trace!("get workspace member info from remote: {}", workspace_id);
|
||||
|
@ -638,8 +639,9 @@ impl UserManager {
|
|||
success: SuccessWorkspaceSubscriptionPB,
|
||||
) -> FlowyResult<()> {
|
||||
// periodically check the billing state
|
||||
let workspace_id = Uuid::from_str(&success.workspace_id)?;
|
||||
let plans = PeriodicallyCheckBillingState::new(
|
||||
success.workspace_id,
|
||||
workspace_id,
|
||||
success.plan.map(SubscriptionPlan::from),
|
||||
Arc::downgrade(&self.cloud_services),
|
||||
Arc::downgrade(&self.authenticate_user),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue