Skip to content

Commit 14f4798

Browse files
committed
chore: stream search result
1 parent 952c10f commit 14f4798

File tree

19 files changed

+191
-283
lines changed

19 files changed

+191
-283
lines changed

frontend/appflowy_flutter/lib/workspace/application/command_palette/command_palette_bloc.dart

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'dart:async';
22

33
import 'package:appflowy/plugins/trash/application/trash_listener.dart';
44
import 'package:appflowy/plugins/trash/application/trash_service.dart';
5-
import 'package:appflowy/workspace/application/command_palette/search_listener.dart';
65
import 'package:appflowy/workspace/application/command_palette/search_service.dart';
76
import 'package:appflowy_backend/protobuf/flowy-folder/trash.pb.dart';
87
import 'package:appflowy_backend/protobuf/flowy-search/notification.pb.dart';
@@ -13,33 +12,22 @@ import 'package:freezed_annotation/freezed_annotation.dart';
1312

1413
part 'command_palette_bloc.freezed.dart';
1514

16-
const _searchChannel = 'CommandPalette';
17-
1815
class CommandPaletteBloc
1916
extends Bloc<CommandPaletteEvent, CommandPaletteState> {
2017
CommandPaletteBloc() : super(CommandPaletteState.initial()) {
21-
_searchListener.start(
22-
onResultsChanged: _onResultsChanged,
23-
);
24-
2518
_initTrash();
2619
_dispatch();
2720
}
2821

2922
Timer? _debounceOnChanged;
3023
final TrashService _trashService = TrashService();
31-
final SearchListener _searchListener = SearchListener(
32-
channel: _searchChannel,
33-
);
3424
final TrashListener _trashListener = TrashListener();
3525
String? _oldQuery;
3626
String? _workspaceId;
37-
int _messagesReceived = 0;
3827

3928
@override
4029
Future<void> close() {
4130
_trashListener.close();
42-
_searchListener.stop();
4331
_debounceOnChanged?.cancel();
4432
return super.close();
4533
}
@@ -67,10 +55,23 @@ class CommandPaletteBloc
6755
if (search.isNotEmpty && search != state.query) {
6856
_oldQuery = state.query;
6957
emit(state.copyWith(query: search, isLoading: true));
70-
await SearchBackendService.performSearch(
71-
search,
72-
workspaceId: _workspaceId,
73-
channel: _searchChannel,
58+
unawaited(
59+
SearchBackendService.performSearch(
60+
search,
61+
workspaceId: _workspaceId,
62+
).then(
63+
(result) {
64+
result.onSuccess(
65+
(stream) async {
66+
if (!isClosed) {
67+
add(
68+
CommandPaletteEvent.newSearchStream(stream: stream),
69+
);
70+
}
71+
},
72+
);
73+
},
74+
),
7475
);
7576
} else {
7677
emit(
@@ -83,30 +84,41 @@ class CommandPaletteBloc
8384
);
8485
}
8586
},
86-
resultsChanged: (SearchResultNotificationPB notification) {
87+
newSearchStream: (SearchResponseStream stream) {
88+
if (state.searchResponseStream != null) {
89+
state.searchResponseStream!.dispose();
90+
}
91+
92+
emit(state.copyWith(searchId: stream.searchId));
93+
stream.listen(
94+
onData: (SearchResponsePB response) {
95+
if (!isClosed) {
96+
add(CommandPaletteEvent.resultsChanged(response: response));
97+
}
98+
},
99+
);
100+
},
101+
resultsChanged: (SearchResponsePB response) {
87102
if (state.query != _oldQuery) {
88103
emit(
89104
state.copyWith(
90105
resultItems: [],
91106
resultSummaries: [],
92-
isLoading: true,
107+
isLoading: response.isLoading,
93108
),
94109
);
95110
_oldQuery = state.query;
96-
_messagesReceived = 0;
97111
}
98112

99-
if (state.query != notification.query) {
113+
if (state.searchId != response.searchId) {
100114
return;
101115
}
102116

103-
_messagesReceived++;
104-
105117
emit(
106118
state.copyWith(
107-
resultItems: notification.result.items,
108-
resultSummaries: notification.result.summaries,
109-
isLoading: _messagesReceived != notification.sends.toInt(),
119+
resultItems: response.result.items,
120+
resultSummaries: response.result.summaries,
121+
isLoading: response.isLoading,
110122
),
111123
);
112124
},
@@ -128,6 +140,7 @@ class CommandPaletteBloc
128140
resultSummaries: [],
129141
query: '',
130142
isLoading: false,
143+
searchId: null,
131144
),
132145
);
133146
},
@@ -159,9 +172,6 @@ class CommandPaletteBloc
159172

160173
void _performSearch(String value) =>
161174
add(CommandPaletteEvent.performSearch(search: value));
162-
163-
void _onResultsChanged(SearchResultNotificationPB results) =>
164-
add(CommandPaletteEvent.resultsChanged(results: results));
165175
}
166176

167177
@freezed
@@ -172,8 +182,12 @@ class CommandPaletteEvent with _$CommandPaletteEvent {
172182
const factory CommandPaletteEvent.performSearch({required String search}) =
173183
_PerformSearch;
174184

185+
const factory CommandPaletteEvent.newSearchStream({
186+
required SearchResponseStream stream,
187+
}) = _NewSearchStream;
188+
175189
const factory CommandPaletteEvent.resultsChanged({
176-
required SearchResultNotificationPB results,
190+
required SearchResponsePB response,
177191
}) = _ResultsChanged;
178192

179193
const factory CommandPaletteEvent.trashChanged({
@@ -195,8 +209,10 @@ class CommandPaletteState with _$CommandPaletteState {
195209
@Default(null) String? query,
196210
@Default([]) List<SearchResponseItemPB> resultItems,
197211
@Default([]) List<SearchSummaryPB> resultSummaries,
212+
@Default(null) SearchResponseStream? searchResponseStream,
198213
required bool isLoading,
199214
@Default([]) List<TrashPB> trash,
215+
@Default(null) String? searchId,
200216
}) = _CommandPaletteState;
201217

202218
factory CommandPaletteState.initial() => CommandPaletteState(

frontend/appflowy_flutter/lib/workspace/application/command_palette/search_listener.dart

Lines changed: 0 additions & 74 deletions
This file was deleted.
Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,67 @@
1+
import 'dart:async';
2+
import 'dart:ffi';
3+
import 'dart:isolate';
4+
import 'dart:typed_data';
5+
16
import 'package:appflowy_backend/dispatch/dispatch.dart';
27
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
8+
import 'package:appflowy_backend/protobuf/flowy-search/notification.pb.dart';
39
import 'package:appflowy_backend/protobuf/flowy-search/query.pb.dart';
410
import 'package:appflowy_backend/protobuf/flowy-search/search_filter.pb.dart';
511
import 'package:appflowy_result/appflowy_result.dart';
12+
import 'package:nanoid/nanoid.dart';
13+
import 'package:fixnum/fixnum.dart';
614

715
class SearchBackendService {
8-
static Future<FlowyResult<void, FlowyError>> performSearch(
16+
static Future<FlowyResult<SearchResponseStream, FlowyError>> performSearch(
917
String keyword, {
1018
String? workspaceId,
11-
String? channel,
1219
}) async {
20+
final searchId = nanoid(6);
21+
final stream = SearchResponseStream(searchId: searchId);
22+
1323
final filter = SearchFilterPB(workspaceId: workspaceId);
1424
final request = SearchQueryPB(
1525
search: keyword,
1626
filter: filter,
17-
channel: channel,
27+
searchId: searchId,
28+
streamPort: Int64(stream.nativePort),
29+
);
30+
31+
unawaited(SearchEventSearch(request).send());
32+
return FlowyResult.success(stream);
33+
}
34+
}
35+
36+
class SearchResponseStream {
37+
SearchResponseStream({required this.searchId}) {
38+
_port.handler = _controller.add;
39+
_subscription = _controller.stream.listen(
40+
(Uint8List data) => _onResultsChanged(data),
1841
);
42+
}
43+
44+
final String searchId;
45+
final RawReceivePort _port = RawReceivePort();
46+
final StreamController<Uint8List> _controller = StreamController.broadcast();
47+
late StreamSubscription<Uint8List> _subscription;
48+
void Function(SearchResponsePB response)? _onData;
49+
50+
int get nativePort => _port.sendPort.nativePort;
51+
52+
Future<void> dispose() async {
53+
await _subscription.cancel();
54+
_port.close();
55+
}
56+
57+
void _onResultsChanged(Uint8List data) {
58+
final response = SearchResponsePB.fromBuffer(data);
59+
_onData?.call(response);
60+
}
1961

20-
return SearchEventSearch(request).send();
62+
void listen({
63+
required void Function(SearchResponsePB response)? onData,
64+
}) {
65+
_onData = onData;
2166
}
2267
}

frontend/appflowy_flutter/macos/Podfile.lock

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -144,34 +144,34 @@ EXTERNAL SOURCES:
144144
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
145145

146146
SPEC CHECKSUMS:
147-
app_links: 9028728e32c83a0831d9db8cf91c526d16cc5468
148-
appflowy_backend: 464aeb3e5c6966a41641a2111e5ead72ce2695f7
149-
auto_updater_macos: 3a42f1a06be6981f1a18be37e6e7bf86aa732118
150-
bitsdojo_window_macos: 7959fb0ca65a3ccda30095c181ecb856fae48ea9
151-
connectivity_plus: e74b9f74717d2d99d45751750e266e55912baeb5
152-
desktop_drop: e0b672a7d84c0a6cbc378595e82cdb15f2970a43
153-
device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041
154-
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
155-
flowy_infra_ui: 8760ff42a789de40bf5007a5f176b454722a341e
147+
app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a
148+
appflowy_backend: 865496343de667fc8c600e04b9fd05234e130cf9
149+
auto_updater_macos: 3e3462c418fe4e731917eacd8d28eef7af84086d
150+
bitsdojo_window_macos: 44e3b8fe3dd463820e0321f6256c5b1c16bb6a00
151+
connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747
152+
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
153+
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
154+
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
155+
flowy_infra_ui: 03301a39ad118771adbf051a664265c61c507f38
156156
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
157157
HotKey: 400beb7caa29054ea8d864c96f5ba7e5b4852277
158-
hotkey_manager: b443f35f4d772162937aa73fd8995e579f8ac4e2
159-
irondash_engine_context: 893c7d96d20ce361d7e996f39d360c4c2f9869ba
160-
local_notifier: ebf072651e35ae5e47280ad52e2707375cb2ae4e
161-
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
162-
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
158+
hotkey_manager: c32bf0bfe8f934b7bc17ab4ad5c4c142960b023c
159+
irondash_engine_context: da62996ee25616d2f01bbeb85dc115d813359478
160+
local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff
161+
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
162+
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
163163
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
164-
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
164+
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
165165
Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1
166-
sentry_flutter: e24b397f9a61fa5bbefd8279c3b2242ca86faa90
167-
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
168-
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
166+
sentry_flutter: a39c2a2d67d5e5b9cb0b94a4985c76dd5b3fc737
167+
share_plus: 1fa619de8392a4398bfaf176d441853922614e89
168+
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
169169
Sparkle: 5f8960a7a119aa7d45dacc0d5837017170bc5675
170-
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
171-
super_native_extensions: c2795d6d9aedf4a79fae25cb6160b71b50549189
172-
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
173-
webview_flutter_wkwebview: 44d4dee7d7056d5ad185d25b38404436d56c547c
174-
window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c
170+
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
171+
super_native_extensions: 85efee3a7495b46b04befcfc86ed12069264ebf3
172+
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
173+
webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4
174+
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
175175

176176
PODFILE CHECKSUM: 0532f3f001ca3110b8be345d6491fff690e95823
177177

0 commit comments

Comments
 (0)