chore: sync chat document when open chat (#7016)

* chore: sync document

* chore: auto create chat title
This commit is contained in:
Nathan.fooo 2024-12-20 00:15:01 +08:00 committed by GitHub
parent ee96a44fef
commit d25a399aba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 425 additions and 184 deletions

View File

@ -6,6 +6,7 @@ import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/code.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:collection/collection.dart';
import 'package:fixnum/fixnum.dart';
@ -64,6 +65,9 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
Future<void> close() async {
await answerStream?.dispose();
await listener.stop();
final request = ViewIdPB(value: chatId);
unawaited(FolderEventCloseView(request).send());
return super.close();
}

View File

@ -172,7 +172,7 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bincode",
@ -192,7 +192,7 @@ dependencies = [
[[package]]
name = "appflowy-ai-client"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bytes",
@ -888,7 +888,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.2.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"again",
"anyhow",
@ -944,7 +944,7 @@ dependencies = [
[[package]]
name = "client-api-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"collab-entity",
"collab-rt-entity",
@ -957,7 +957,7 @@ dependencies = [
[[package]]
name = "client-websocket"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"futures-channel",
"futures-util",
@ -1257,7 +1257,7 @@ dependencies = [
[[package]]
name = "collab-rt-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bincode",
@ -1282,7 +1282,7 @@ dependencies = [
[[package]]
name = "collab-rt-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"async-trait",
@ -1554,7 +1554,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa 1.0.6",
"phf 0.11.2",
"phf 0.8.0",
"smallvec",
]
@ -1679,7 +1679,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",
@ -3268,7 +3268,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"futures-util",
@ -3285,7 +3285,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",
@ -3840,7 +3840,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bytes",
@ -6576,7 +6576,7 @@ dependencies = [
[[package]]
name = "shared-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",

View File

@ -59,7 +59,7 @@ collab-importer = { version = "0.1" }
# Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9f57fa63d5ee039f50b0d27b860679deb14fee2e" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ea131f0baab67defe7591067357eced490072372" }
[dependencies]
serde_json.workspace = true

View File

@ -163,7 +163,7 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bincode",
@ -183,7 +183,7 @@ dependencies = [
[[package]]
name = "appflowy-ai-client"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bytes",
@ -877,7 +877,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.2.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"again",
"anyhow",
@ -933,7 +933,7 @@ dependencies = [
[[package]]
name = "client-api-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"collab-entity",
"collab-rt-entity",
@ -946,7 +946,7 @@ dependencies = [
[[package]]
name = "client-websocket"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"futures-channel",
"futures-util",
@ -1255,7 +1255,7 @@ dependencies = [
[[package]]
name = "collab-rt-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bincode",
@ -1280,7 +1280,7 @@ dependencies = [
[[package]]
name = "collab-rt-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"async-trait",
@ -1559,7 +1559,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa 1.0.10",
"phf 0.11.2",
"phf 0.8.0",
"smallvec",
]
@ -1684,7 +1684,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",
@ -3350,7 +3350,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"futures-util",
@ -3367,7 +3367,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",
@ -3927,7 +3927,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bytes",
@ -6656,7 +6656,7 @@ dependencies = [
[[package]]
name = "shared-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",

View File

@ -58,7 +58,7 @@ collab-importer = { version = "0.1" }
# Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9f57fa63d5ee039f50b0d27b860679deb14fee2e" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ea131f0baab67defe7591067357eced490072372" }
[dependencies]
serde_json.workspace = true

View File

@ -163,7 +163,7 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bincode",
@ -183,7 +183,7 @@ dependencies = [
[[package]]
name = "appflowy-ai-client"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bytes",
@ -780,7 +780,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.2.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"again",
"anyhow",
@ -836,7 +836,7 @@ dependencies = [
[[package]]
name = "client-api-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"collab-entity",
"collab-rt-entity",
@ -849,7 +849,7 @@ dependencies = [
[[package]]
name = "client-websocket"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"futures-channel",
"futures-util",
@ -1118,7 +1118,7 @@ dependencies = [
[[package]]
name = "collab-rt-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bincode",
@ -1143,7 +1143,7 @@ dependencies = [
[[package]]
name = "collab-rt-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"async-trait",
@ -1538,7 +1538,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",
@ -2982,7 +2982,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"futures-util",
@ -2999,7 +2999,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",
@ -3484,7 +3484,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"bytes",
@ -5841,7 +5841,7 @@ dependencies = [
[[package]]
name = "shared-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372"
dependencies = [
"anyhow",
"app-error",

View File

@ -107,8 +107,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 = "9f57fa63d5ee039f50b0d27b860679deb14fee2e" }
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9f57fa63d5ee039f50b0d27b860679deb14fee2e" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ea131f0baab67defe7591067357eced490072372" }
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ea131f0baab67defe7591067357eced490072372" }
[profile.dev]
opt-level = 0

View File

@ -1,4 +1,4 @@
use flowy_folder::view_operation::{EncodedCollabType, ViewData};
use flowy_folder::view_operation::{GatherEncodedCollab, ViewData};
use std::sync::Arc;
use collab_folder::{FolderData, View};
@ -190,14 +190,14 @@ impl EventIntegrationTest {
payload.unwrap()
}
pub async fn get_encoded_collab_v1_from_disk(
pub async fn gather_encode_collab_from_disk(
&self,
view_id: &str,
layout: ViewLayout,
) -> EncodedCollabType {
) -> GatherEncodedCollab {
self
.folder_manager
.get_encode_collab_from_disk(view_id, &layout)
.gather_publish_encode_collab(view_id, &layout)
.await
.unwrap()
}

View File

@ -5,7 +5,7 @@ use event_integration_test::EventIntegrationTest;
use flowy_folder::entities::{
ImportItemPayloadPB, ImportPayloadPB, ImportTypePB, ViewLayoutPB, ViewPB,
};
use flowy_folder::view_operation::EncodedCollabType;
use flowy_folder::view_operation::GatherEncodedCollab;
use crate::util::unzip;
@ -18,11 +18,11 @@ async fn publish_single_database_test() {
let grid = import_csv("publish_grid_primary.csv", &test).await;
let grid_encoded_collab = test
.get_encoded_collab_v1_from_disk(&grid.id, ViewLayout::Grid)
.gather_encode_collab_from_disk(&grid.id, ViewLayout::Grid)
.await;
match grid_encoded_collab {
EncodedCollabType::Database(encoded_collab) => {
GatherEncodedCollab::Database(encoded_collab) => {
// the len of row collabs should be the same as the number of rows in the csv file
let rows_len = encoded_collab.database_row_encoded_collabs.len();
assert_eq!(rows_len, 18);
@ -106,11 +106,11 @@ async fn test_publish_encode_collab_result(
test.open_database(&id).await;
let encoded_collab = test
.get_encoded_collab_v1_from_disk(&id, layout.into())
.gather_encode_collab_from_disk(&id, layout.into())
.await;
match encoded_collab {
EncodedCollabType::Database(encoded_collab) => {
GatherEncodedCollab::Database(encoded_collab) => {
if let Some(rows_len) = expectations.get(&view.name.as_str()) {
assert_eq!(encoded_collab.database_row_encoded_collabs.len(), *rows_len);
}

View File

@ -2,7 +2,7 @@ use collab_folder::ViewLayout;
use event_integration_test::EventIntegrationTest;
use flowy_folder::entities::{ViewLayoutPB, ViewPB};
use flowy_folder::publish_util::generate_publish_name;
use flowy_folder::view_operation::EncodedCollabType;
use flowy_folder::view_operation::GatherEncodedCollab;
use flowy_folder_pub::entities::{
PublishDocumentPayload, PublishPayload, PublishViewInfo, PublishViewMeta, PublishViewMetaData,
};
@ -14,7 +14,7 @@ async fn mock_single_document_view_publish_payload(
) -> Vec<PublishPayload> {
let view_id = &view.id;
let layout: ViewLayout = view.layout.clone().into();
let view_encoded_collab = test.get_encoded_collab_v1_from_disk(view_id, layout).await;
let view_encoded_collab = test.gather_encode_collab_from_disk(view_id, layout).await;
let publish_view_info = PublishViewInfo {
view_id: view_id.to_string(),
name: view.name.to_string(),
@ -29,7 +29,7 @@ async fn mock_single_document_view_publish_payload(
};
let data = match view_encoded_collab {
EncodedCollabType::Document(doc) => doc.document_encoded_collab.doc_state.to_vec(),
GatherEncodedCollab::Document(doc) => doc.doc_state.to_vec(),
_ => panic!("Expected document collab"),
};
@ -54,7 +54,7 @@ async fn mock_nested_document_view_publish_payload(
) -> Vec<PublishPayload> {
let view_id = &view.id;
let layout: ViewLayout = view.layout.clone().into();
let view_encoded_collab = test.get_encoded_collab_v1_from_disk(view_id, layout).await;
let view_encoded_collab = test.gather_encode_collab_from_disk(view_id, layout).await;
let publish_view_info = PublishViewInfo {
view_id: view_id.to_string(),
name: view.name.to_string(),
@ -72,7 +72,7 @@ async fn mock_nested_document_view_publish_payload(
let child_view = test.get_view(child_view_id).await;
let child_layout: ViewLayout = child_view.layout.clone().into();
let child_view_encoded_collab = test
.get_encoded_collab_v1_from_disk(child_view_id, child_layout)
.gather_encode_collab_from_disk(child_view_id, child_layout)
.await;
let child_publish_view_info = PublishViewInfo {
view_id: child_view_id.to_string(),
@ -89,12 +89,12 @@ async fn mock_nested_document_view_publish_payload(
let child_publish_name = generate_publish_name(&child_view.id, &child_view.name);
let data = match view_encoded_collab {
EncodedCollabType::Document(doc) => doc.document_encoded_collab.doc_state.to_vec(),
GatherEncodedCollab::Document(doc) => doc.doc_state.to_vec(),
_ => panic!("Expected document collab"),
};
let child_data = match child_view_encoded_collab {
EncodedCollabType::Document(doc) => doc.document_encoded_collab.doc_state.to_vec(),
GatherEncodedCollab::Document(doc) => doc.doc_state.to_vec(),
_ => panic!("Expected document collab"),
};

View File

@ -1,6 +1,6 @@
use crate::chat::Chat;
use crate::entities::{
ChatInfoPB, ChatMessageListPB, ChatMessagePB, FilePB, RepeatedRelatedQuestionPB,
ChatInfoPB, ChatMessageListPB, ChatMessagePB, ChatSettingsPB, FilePB, RepeatedRelatedQuestionPB,
};
use crate::local_ai::local_llm_chat::LocalAIController;
use crate::middleware::chat_service_mw::AICloudServiceMiddleware;
@ -9,18 +9,19 @@ use crate::persistence::{insert_chat, read_chat_metadata, ChatTable};
use appflowy_plugin::manager::PluginManager;
use dashmap::DashMap;
use flowy_ai_pub::cloud::{
ChatCloudService, ChatMessageMetadata, ChatMessageType, UpdateChatParams,
ChatCloudService, ChatMessageMetadata, ChatMessageType, ChatSettings, UpdateChatParams,
};
use flowy_error::{FlowyError, FlowyResult};
use flowy_sqlite::kv::KVStorePreferences;
use flowy_sqlite::DBConnection;
use crate::notification::{chat_notification_builder, ChatNotification};
use flowy_storage_pub::storage::StorageService;
use lib_infra::async_trait::async_trait;
use lib_infra::util::timestamp;
use std::path::PathBuf;
use std::sync::{Arc, Weak};
use tracing::{info, trace};
use tracing::{error, info, trace};
pub trait AIUserService: Send + Sync + 'static {
fn user_id(&self) -> Result<i64, FlowyError>;
@ -31,22 +32,29 @@ pub trait AIUserService: Send + Sync + 'static {
}
#[async_trait]
pub trait AIQueryService: 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>;
async fn sync_rag_documents(&self, rag_ids: Vec<String>) -> Result<(), FlowyError>;
async fn sync_rag_documents(
&self,
workspace_id: &str,
rag_ids: Vec<String>,
) -> Result<(), FlowyError>;
async fn notify_did_send_message(&self, chat_id: &str, message: &str) -> Result<(), FlowyError>;
}
pub struct AIManager {
pub cloud_service_wm: Arc<AICloudServiceMiddleware>,
pub user_service: Arc<dyn AIUserService>,
pub query_service: Arc<dyn AIQueryService>,
pub external_service: Arc<dyn AIExternalService>,
chats: Arc<DashMap<String, Arc<Chat>>>,
pub local_ai_controller: Arc<LocalAIController>,
store_preferences: Arc<KVStorePreferences>,
}
impl AIManager {
@ -55,7 +63,7 @@ impl AIManager {
user_service: impl AIUserService,
store_preferences: Arc<KVStorePreferences>,
storage_service: Weak<dyn StorageService>,
query_service: impl AIQueryService,
query_service: impl AIExternalService,
) -> AIManager {
let user_service = Arc::new(user_service);
let plugin_manager = Arc::new(PluginManager::new());
@ -65,7 +73,7 @@ impl AIManager {
user_service.clone(),
chat_cloud_service.clone(),
));
let query_service = Arc::new(query_service);
let external_service = Arc::new(query_service);
// setup local chat service
let cloud_service_wm = Arc::new(AICloudServiceMiddleware::new(
@ -80,7 +88,8 @@ impl AIManager {
user_service,
chats: Arc::new(DashMap::new()),
local_ai_controller,
query_service,
external_service,
store_preferences,
}
}
@ -99,12 +108,41 @@ impl AIManager {
self.cloud_service_wm.clone(),
))
});
trace!("[AI Plugin] notify open chat: {}", chat_id);
if self.local_ai_controller.is_running() {
self.local_ai_controller.open_chat(chat_id);
}
let user_service = self.user_service.clone();
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();
tokio::spawn(async move {
match refresh_chat_setting(
&user_service,
&cloud_service_wm,
&store_preferences,
&chat_id,
)
.await
{
Ok(settings) => {
if settings.rag_ids.is_empty() {
return;
}
if let Ok(workspace_id) = user_service.workspace_id() {
let _ = external_service
.sync_rag_documents(&workspace_id, settings.rag_ids)
.await;
}
},
Err(err) => {
error!("failed to refresh chat settings: {}", err);
},
}
});
Ok(())
}
@ -152,7 +190,7 @@ impl AIManager {
) -> Result<Arc<Chat>, FlowyError> {
let workspace_id = self.user_service.workspace_id()?;
let rag_ids = self
.query_service
.external_service
.query_chat_rag_ids(parent_view_id, chat_id)
.await
.unwrap_or_default();
@ -193,6 +231,10 @@ impl AIManager {
metadata,
)
.await?;
let _ = self
.external_service
.notify_did_send_message(chat_id, message)
.await;
Ok(question)
}
@ -302,31 +344,48 @@ impl AIManager {
Ok(())
}
pub fn local_ai_purchased(&self) {}
pub async fn get_rag_ids(&self, chat_id: &str) -> FlowyResult<Vec<String>> {
let workspace_id = self.user_service.workspace_id()?;
let settings = self
.cloud_service_wm
.get_chat_settings(&workspace_id, chat_id)
.await?;
if let Some(settings) = self
.store_preferences
.get_object::<ChatSettings>(&setting_store_key(chat_id))
{
return Ok(settings.rag_ids);
}
let settings = refresh_chat_setting(
&self.user_service,
&self.cloud_service_wm,
&self.store_preferences,
chat_id,
)
.await?;
Ok(settings.rag_ids)
}
pub async fn update_rag_ids(&self, chat_id: &str, rag_ids: Vec<String>) -> FlowyResult<()> {
info!("[Chat] update chat:{} rag ids: {:?}", chat_id, rag_ids);
if !rag_ids.is_empty() {
let workspace_id = self.user_service.workspace_id()?;
let update_setting = UpdateChatParams {
name: None,
metadata: None,
rag_ids: Some(rag_ids),
rag_ids: Some(rag_ids.clone()),
};
self
.cloud_service_wm
.update_chat_settings(&workspace_id, chat_id, update_setting)
.await?;
let user_service = self.user_service.clone();
let external_service = self.external_service.clone();
tokio::spawn(async move {
if let Ok(workspace_id) = user_service.workspace_id() {
let _ = external_service
.sync_rag_documents(&workspace_id, rag_ids)
.await;
}
});
}
Ok(())
}
@ -346,3 +405,32 @@ fn save_chat(conn: DBConnection, chat_id: &str) -> FlowyResult<()> {
insert_chat(conn, &row)?;
Ok(())
}
async fn refresh_chat_setting(
user_service: &Arc<dyn AIUserService>,
cloud_service: &Arc<AICloudServiceMiddleware>,
store_preferences: &Arc<KVStorePreferences>,
chat_id: &str,
) -> FlowyResult<ChatSettings> {
info!("[Chat] refresh chat:{} setting", chat_id);
let workspace_id = user_service.workspace_id()?;
let settings = cloud_service
.get_chat_settings(&workspace_id, chat_id)
.await?;
if let Err(err) = store_preferences.set_object(&setting_store_key(chat_id), &settings) {
error!("failed to set chat settings: {}", err);
}
chat_notification_builder(chat_id, 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)
}

View File

@ -14,6 +14,7 @@ pub enum ChatNotification {
FinishStreaming = 5,
UpdateChatPluginState = 6,
UpdateLocalChatAI = 7,
DidUpdateChatSettings = 8,
}
impl std::convert::From<ChatNotification> for i32 {

View File

@ -1,8 +1,10 @@
use flowy_ai::ai_manager::{AIManager, AIQueryService, AIUserService};
use collab_entity::CollabType;
use flowy_ai::ai_manager::{AIExternalService, AIManager, AIUserService};
use flowy_ai_pub::cloud::ChatCloudService;
use flowy_error::FlowyError;
use flowy_folder::ViewLayout;
use flowy_folder_pub::query::FolderQueryService;
use flowy_folder_pub::cloud::{FolderCloudService, FullSyncCollabParams};
use flowy_folder_pub::query::FolderService;
use flowy_sqlite::kv::KVStorePreferences;
use flowy_sqlite::DBConnection;
use flowy_storage_pub::storage::StorageService;
@ -10,6 +12,7 @@ use flowy_user::services::authenticate_user::AuthenticateUser;
use lib_infra::async_trait::async_trait;
use std::path::PathBuf;
use std::sync::{Arc, Weak};
use tracing::{error, info};
pub struct ChatDepsResolver;
@ -19,7 +22,8 @@ impl ChatDepsResolver {
cloud_service: Arc<dyn ChatCloudService>,
store_preferences: Arc<KVStorePreferences>,
storage_service: Weak<dyn StorageService>,
folder_query: impl FolderQueryService,
folder_cloud_service: Arc<dyn FolderCloudService>,
folder_service: impl FolderService,
) -> Arc<AIManager> {
let user_service = ChatUserServiceImpl(authenticate_user);
Arc::new(AIManager::new(
@ -28,25 +32,27 @@ impl ChatDepsResolver {
store_preferences,
storage_service,
ChatQueryServiceImpl {
folder_query: Box::new(folder_query),
folder_service: Box::new(folder_service),
folder_cloud_service,
},
))
}
}
struct ChatQueryServiceImpl {
folder_query: Box<dyn FolderQueryService>,
folder_service: Box<dyn FolderService>,
folder_cloud_service: Arc<dyn FolderCloudService>,
}
#[async_trait]
impl AIQueryService for ChatQueryServiceImpl {
impl AIExternalService for ChatQueryServiceImpl {
async fn query_chat_rag_ids(
&self,
parent_view_id: &str,
chat_id: &str,
) -> Result<Vec<String>, FlowyError> {
let mut ids = self
.folder_query
.folder_service
.get_sibling_ids_with_view_layout(parent_view_id, ViewLayout::Document)
.await;
@ -57,14 +63,48 @@ impl AIQueryService for ChatQueryServiceImpl {
Ok(ids)
}
async fn sync_rag_documents(&self, rag_ids: Vec<String>) -> Result<(), FlowyError> {
async fn sync_rag_documents(
&self,
workspace_id: &str,
rag_ids: Vec<String>,
) -> Result<(), FlowyError> {
info!("sync_rag_documents: {:?}", rag_ids);
for rag_id in rag_ids.iter() {
if let Some(_query_collab) = self.folder_query.get_collab(rag_id).await {
// TODO(nathan): sync
if let Some(query_collab) = self
.folder_service
.get_collab(rag_id, CollabType::Document)
.await
{
let params = FullSyncCollabParams {
object_id: rag_id.clone(),
collab_type: CollabType::Document,
encoded_collab: query_collab.encoded_collab,
};
match self
.folder_cloud_service
.full_sync_collab_object(workspace_id, params)
.await
{
Ok(_) => info!("[Chat] full sync rag document: {}", rag_id),
Err(err) => error!("failed to sync rag document:{} error:{}", rag_id, err),
}
}
}
Ok(())
}
async fn notify_did_send_message(&self, chat_id: &str, message: &str) -> Result<(), FlowyError> {
info!(
"notify_did_send_message: chat_id: {}, message: {}",
chat_id, message
);
self
.folder_service
.set_view_title_if_empty(chat_id, message)
.await?;
Ok(())
}
}
struct ChatUserServiceImpl(Weak<AuthenticateUser>);

View File

@ -12,13 +12,12 @@ use flowy_database2::DatabaseManager;
use flowy_document::entities::DocumentDataPB;
use flowy_document::manager::DocumentManager;
use flowy_document::parser::json::parser::JsonToDocumentParser;
use flowy_error::{FlowyError, FlowyResult};
use flowy_folder::entities::{CreateViewParams, ViewLayoutPB};
use flowy_error::{internal_error, FlowyError, FlowyResult};
use flowy_folder::entities::{CreateViewParams, UpdateViewParams, ViewLayoutPB};
use flowy_folder::manager::{FolderManager, FolderUser};
use flowy_folder::share::ImportType;
use flowy_folder::view_operation::{
DatabaseEncodedCollab, DocumentEncodedCollab, EncodedCollabType, FolderOperationHandler,
ImportedData, View, ViewData,
DatabaseEncodedCollab, FolderOperationHandler, GatherEncodedCollab, ImportedData, View, ViewData,
};
use flowy_folder::ViewLayout;
use flowy_search::folder::indexer::FolderIndexManagerImpl;
@ -34,7 +33,7 @@ use tokio::sync::RwLock;
use crate::integrate::server::ServerProvider;
use collab_plugins::local_storage::kv::KVTransactionDB;
use flowy_folder_pub::query::{FolderQueryService, QueryCollab};
use flowy_folder_pub::query::{FolderQueryService, FolderService, FolderViewEdit, QueryCollab};
use lib_infra::async_trait::async_trait;
pub struct FolderDepsResolver();
@ -116,6 +115,10 @@ impl FolderUser for FolderUserImpl {
struct DocumentFolderOperation(Arc<DocumentManager>);
#[async_trait]
impl FolderOperationHandler for DocumentFolderOperation {
fn name(&self) -> &str {
"DocumentFolderOperationHandler"
}
async fn create_workspace_view(
&self,
uid: i64,
@ -169,6 +172,16 @@ impl FolderOperationHandler for DocumentFolderOperation {
Ok(data_bytes)
}
async fn gather_publish_encode_collab(
&self,
user: &Arc<dyn FolderUser>,
view_id: &str,
) -> Result<GatherEncodedCollab, FlowyError> {
let encoded_collab =
get_encoded_collab_v1_from_disk(user, view_id, CollabType::Document).await?;
Ok(GatherEncodedCollab::Document(encoded_collab))
}
async fn create_view_with_view_data(
&self,
user_id: i64,
@ -209,47 +222,6 @@ impl FolderOperationHandler for DocumentFolderOperation {
}
}
async fn get_encoded_collab_v1_from_disk(
&self,
user: &Arc<dyn FolderUser>,
view_id: &str,
) -> Result<EncodedCollabType, FlowyError> {
// get the collab_object_id for the document.
// the collab_object_id for the document is the view_id.
let workspace_id = user.workspace_id()?;
let uid = user
.user_id()
.map_err(|e| e.with_context("unable to get the uid: {}"))?;
// get the collab db
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(|| {
FlowyError::internal().with_context(
"The collab db has been dropped, indicating that the user has switched to a new account",
)
})?;
let collab_read_txn = collab_db.read_txn();
// read the collab from the db
let collab =
load_collab_by_object_id(uid, &collab_read_txn, &workspace_id, view_id).map_err(|e| {
FlowyError::internal().with_context(format!("load document collab failed: {}", e))
})?;
let encoded_collab = collab
// encode the collab and check the integrity of the collab
.encode_collab_v1(|collab| CollabType::Document.validate_require_data(collab))
.map_err(|e| {
FlowyError::internal().with_context(format!("encode document collab failed: {}", e))
})?;
Ok(EncodedCollabType::Document(DocumentEncodedCollab {
document_encoded_collab: encoded_collab,
}))
}
async fn import_from_bytes(
&self,
uid: i64,
@ -279,10 +251,6 @@ impl FolderOperationHandler for DocumentFolderOperation {
// TODO(lucas): import file from local markdown file
Ok(())
}
fn name(&self) -> &str {
"DocumentFolderOperationHandler"
}
}
struct DatabaseFolderOperation(Arc<DatabaseManager>);
@ -307,11 +275,11 @@ impl FolderOperationHandler for DatabaseFolderOperation {
Ok(())
}
async fn get_encoded_collab_v1_from_disk(
async fn gather_publish_encode_collab(
&self,
user: &Arc<dyn FolderUser>,
view_id: &str,
) -> Result<EncodedCollabType, FlowyError> {
) -> Result<GatherEncodedCollab, FlowyError> {
let workspace_id = user.workspace_id()?;
// get the collab_object_id for the database.
//
@ -349,7 +317,6 @@ 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)
.map_err(|e| {
FlowyError::internal().with_context(format!("load database collab failed: {}", e))
@ -403,7 +370,7 @@ impl FolderOperationHandler for DatabaseFolderOperation {
})
.collect::<Result<HashMap<_, _>, FlowyError>>()?;
Ok(EncodedCollabType::Database(DatabaseEncodedCollab {
Ok(GatherEncodedCollab::Database(DatabaseEncodedCollab {
database_encoded_collab,
database_row_encoded_collabs,
database_row_document_encoded_collabs,
@ -663,19 +630,62 @@ impl FolderOperationHandler for ChatFolderOperation {
}
}
#[derive(Clone, Debug)]
pub struct FolderQueryServiceImpl {
#[derive(Clone)]
pub struct FolderServiceImpl {
folder_manager: Weak<FolderManager>,
user: Arc<dyn FolderUser>,
}
impl FolderService for FolderServiceImpl {}
impl FolderQueryServiceImpl {
pub fn new(folder_manager: Weak<FolderManager>) -> Self {
Self { folder_manager }
impl FolderServiceImpl {
pub fn new(
folder_manager: Weak<FolderManager>,
authenticate_user: Weak<AuthenticateUser>,
) -> Self {
let user: Arc<dyn FolderUser> = Arc::new(FolderUserImpl { authenticate_user });
Self {
folder_manager,
user,
}
}
}
#[async_trait]
impl FolderQueryService for FolderQueryServiceImpl {
impl FolderViewEdit for FolderServiceImpl {
async fn set_view_title_if_empty(&self, view_id: &str, 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 view.name.is_empty() {
let title = if title.len() > 50 {
title.chars().take(50).collect()
} else {
title.to_string()
};
folder_manager
.update_view_with_params(UpdateViewParams {
view_id: view_id.to_string(),
name: Some(title),
desc: None,
thumbnail: None,
layout: None,
is_favorite: None,
extra: None,
})
.await?;
}
}
}
Ok(())
}
}
#[async_trait]
impl FolderQueryService for FolderServiceImpl {
async fn get_sibling_ids_with_view_layout(
&self,
parent_view_id: &str,
@ -708,8 +718,52 @@ impl FolderQueryService for FolderQueryServiceImpl {
}
}
async fn get_collab(&self, _object_id: &str) -> Option<QueryCollab> {
// TODO(nathan): return query collab
None
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.clone())
.await
.ok();
encode_collab.map(|encoded_collab| QueryCollab {
collab_type,
encoded_collab,
})
}
}
#[inline]
async fn get_encoded_collab_v1_from_disk(
user: &Arc<dyn FolderUser>,
view_id: &str,
collab_type: CollabType,
) -> Result<EncodedCollab, FlowyError> {
let workspace_id = user.workspace_id()?;
let uid = user
.user_id()
.map_err(|e| e.with_context("unable to get the uid: {}"))?;
// get the collab db
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(|| {
FlowyError::internal().with_context(
"The collab db has been dropped, indicating that the user has switched to a new account",
)
})?;
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| {
FlowyError::internal().with_context(format!("load document collab failed: {}", e))
})?;
tokio::task::spawn_blocking(move || {
let data = collab
.encode_collab_v1(|collab| collab_type.validate_require_data(collab))
.map_err(|e| {
FlowyError::internal().with_context(format!("encode document collab failed: {}", e))
})?;
Ok::<_, FlowyError>(data)
})
.await
.map_err(internal_error)?
}

View File

@ -33,7 +33,8 @@ use flowy_document::deps::DocumentData;
use flowy_document_pub::cloud::{DocumentCloudService, DocumentSnapshot};
use flowy_error::{FlowyError, FlowyResult};
use flowy_folder_pub::cloud::{
FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, Workspace, WorkspaceRecord,
FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, FullSyncCollabParams,
Workspace, WorkspaceRecord,
};
use flowy_folder_pub::entities::PublishPayload;
use flowy_server_pub::af_cloud_config::AFCloudConfiguration;
@ -417,6 +418,18 @@ impl FolderCloudService for ServerProvider {
.import_zip(file_path)
.await
}
async fn full_sync_collab_object(
&self,
workspace_id: &str,
params: FullSyncCollabParams,
) -> Result<(), FlowyError> {
self
.get_server()?
.folder_service()
.full_sync_collab_object(workspace_id, params)
.await
}
}
#[async_trait]

View File

@ -211,21 +211,15 @@ impl UserStatusCallback for UserStatusCallbackImpl {
fn did_update_plans(&self, plans: Vec<SubscriptionPlan>) {
let mut storage_plan_changed = false;
let mut local_ai_enabled = false;
for plan in &plans {
match plan {
SubscriptionPlan::Pro | SubscriptionPlan::Team => storage_plan_changed = true,
SubscriptionPlan::AiLocal => local_ai_enabled = true,
_ => {},
}
}
if storage_plan_changed {
self.storage_manager.enable_storage_write_access();
}
if local_ai_enabled {
self.ai_manager.local_ai_purchased();
}
}
fn did_update_storage_limitation(&self, can_write: bool) {

View File

@ -174,13 +174,17 @@ impl AppFlowyCore {
)
.await;
let folder_query_service = FolderQueryServiceImpl::new(Arc::downgrade(&folder_manager));
let folder_query_service = FolderServiceImpl::new(
Arc::downgrade(&folder_manager),
Arc::downgrade(&authenticate_user),
);
let ai_manager = ChatDepsResolver::resolve(
Arc::downgrade(&authenticate_user),
server_provider.clone(),
store_preference.clone(),
Arc::downgrade(&storage_manager.storage_service),
server_provider.clone(),
folder_query_service.clone(),
);

View File

@ -1,6 +1,7 @@
use crate::entities::PublishPayload;
pub use anyhow::Error;
use client_api::entity::{workspace_dto::PublishInfoView, PublishInfo};
use collab::entity::EncodedCollab;
use collab_entity::CollabType;
pub use collab_folder::{Folder, FolderData, Workspace};
use flowy_error::FlowyError;
@ -40,6 +41,12 @@ pub trait FolderCloudService: Send + Sync + 'static {
object_id: &str,
) -> Result<Vec<u8>, FlowyError>;
async fn full_sync_collab_object(
&self,
workspace_id: &str,
params: FullSyncCollabParams,
) -> Result<(), FlowyError>;
async fn batch_create_folder_collab_objects(
&self,
workspace_id: &str,
@ -105,6 +112,13 @@ pub struct FolderCollabParams {
pub collab_type: CollabType,
}
#[derive(Debug)]
pub struct FullSyncCollabParams {
pub object_id: String,
pub encoded_collab: EncodedCollab,
pub collab_type: CollabType,
}
pub struct FolderSnapshot {
pub snapshot_id: i64,
pub database_id: String,

View File

@ -1,14 +1,16 @@
use collab::entity::EncodedCollab;
use collab_entity::CollabType;
use collab_folder::ViewLayout;
use flowy_error::FlowyResult;
use lib_infra::async_trait::async_trait;
pub struct QueryCollab {
pub name: String,
pub collab_type: CollabType,
pub encoded_collab: EncodedCollab,
}
pub trait FolderService: FolderQueryService + FolderViewEdit {}
#[async_trait]
pub trait FolderQueryService: Send + Sync + 'static {
async fn get_sibling_ids_with_view_layout(
@ -17,5 +19,10 @@ pub trait FolderQueryService: Send + Sync + 'static {
view_layout: ViewLayout,
) -> Vec<String>;
async fn get_collab(&self, object_id: &str) -> Option<QueryCollab>;
async fn get_collab(&self, object_id: &str, 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<()>;
}

View File

@ -16,7 +16,7 @@ use crate::publish_util::{generate_publish_name, view_pb_to_publish_view};
use crate::share::{ImportData, ImportItem, ImportParams};
use crate::util::{folder_not_init_error, workspace_data_not_sync_error};
use crate::view_operation::{
create_view, EncodedCollabType, FolderOperationHandler, FolderOperationHandlers, ViewData,
create_view, FolderOperationHandler, FolderOperationHandlers, GatherEncodedCollab, ViewData,
};
use arc_swap::ArcSwapOption;
use client_api::entity::workspace_dto::PublishInfoView;
@ -132,14 +132,14 @@ impl FolderManager {
Ok(data)
}
pub async fn get_encode_collab_from_disk(
pub async fn gather_publish_encode_collab(
&self,
view_id: &str,
layout: &ViewLayout,
) -> FlowyResult<EncodedCollabType> {
) -> FlowyResult<GatherEncodedCollab> {
let handler = self.get_handler(layout)?;
let encoded_collab = handler
.get_encoded_collab_v1_from_disk(&self.user, view_id)
.gather_publish_encode_collab(&self.user, view_id)
.await?;
Ok(encoded_collab)
}
@ -1524,8 +1524,8 @@ impl FolderManager {
layout: ViewLayout,
) -> FlowyResult<PublishPayload> {
let handler = self.get_handler(&layout)?;
let encoded_collab_wrapper: EncodedCollabType = handler
.get_encoded_collab_v1_from_disk(&self.user, view_id)
let encoded_collab_wrapper: GatherEncodedCollab = handler
.gather_publish_encode_collab(&self.user, view_id)
.await?;
let view = self.get_view_pb(view_id).await?;
@ -1556,7 +1556,7 @@ impl FolderManager {
};
let payload = match encoded_collab_wrapper {
EncodedCollabType::Database(v) => {
GatherEncodedCollab::Database(v) => {
let database_collab = v.database_encoded_collab.doc_state.to_vec();
let database_relations = v.database_relations;
let database_row_collabs = v
@ -1579,11 +1579,11 @@ impl FolderManager {
};
PublishPayload::Database(PublishDatabasePayload { meta, data })
},
EncodedCollabType::Document(v) => {
let data = v.document_encoded_collab.doc_state.to_vec();
GatherEncodedCollab::Document(v) => {
let data = v.doc_state.to_vec();
PublishPayload::Document(PublishDocumentPayload { meta, data })
},
EncodedCollabType::Unknown => PublishPayload::Unknown,
GatherEncodedCollab::Unknown => PublishPayload::Unknown,
};
Ok(payload)

View File

@ -19,17 +19,12 @@ use crate::manager::FolderUser;
use crate::share::ImportType;
#[derive(Debug, Clone)]
pub enum EncodedCollabType {
Document(DocumentEncodedCollab),
pub enum GatherEncodedCollab {
Document(EncodedCollab),
Database(DatabaseEncodedCollab),
Unknown,
}
#[derive(Debug, Clone)]
pub struct DocumentEncodedCollab {
pub document_encoded_collab: EncodedCollab,
}
#[derive(Debug, Clone)]
pub struct DatabaseEncodedCollab {
pub database_encoded_collab: EncodedCollab,
@ -69,11 +64,11 @@ pub trait FolderOperationHandler: Send + Sync {
async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError>;
/// get the encoded collab data from the disk.
async fn get_encoded_collab_v1_from_disk(
async fn gather_publish_encode_collab(
&self,
_user: &Arc<dyn FolderUser>,
_view_id: &str,
) -> Result<EncodedCollabType, FlowyError> {
) -> Result<GatherEncodedCollab, FlowyError> {
Err(FlowyError::not_support())
}

View File

@ -16,8 +16,8 @@ use uuid::Uuid;
use flowy_error::{ErrorCode, FlowyError};
use flowy_folder_pub::cloud::{
Folder, FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, Workspace,
WorkspaceRecord,
Folder, FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, FullSyncCollabParams,
Workspace, WorkspaceRecord,
};
use flowy_folder_pub::entities::PublishPayload;
use lib_infra::async_trait::async_trait;
@ -152,6 +152,25 @@ where
Ok(doc_state)
}
async fn full_sync_collab_object(
&self,
workspace_id: &str,
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(
&workspace_id,
&params.object_id,
params.collab_type,
params.encoded_collab.doc_state.to_vec(),
params.encoded_collab.state_vector.to_vec(),
)
.await?;
Ok(())
}
async fn batch_create_folder_collab_objects(
&self,
workspace_id: &str,

View File

@ -7,8 +7,8 @@ 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, Workspace,
WorkspaceRecord,
gen_workspace_id, FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot,
FullSyncCollabParams, Workspace, WorkspaceRecord,
};
use flowy_folder_pub::entities::PublishPayload;
use lib_infra::async_trait::async_trait;
@ -145,4 +145,12 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
async fn import_zip(&self, _file_path: &str) -> Result<(), FlowyError> {
Err(FlowyError::local_version_not_support())
}
async fn full_sync_collab_object(
&self,
_workspace_id: &str,
_params: FullSyncCollabParams,
) -> Result<(), FlowyError> {
Ok(())
}
}