searchEvent method
Searches searchTerm
in this timeline. It first searches in the
cache, then in the database and then on the server. The search can
take a while, which is why this returns a stream so the already found
events can already be displayed.
Override the searchFunc
if you need another search. This will then
ignore searchTerm
.
Implementation
Stream<List<Event>> searchEvent({
String? searchTerm,
int requestHistoryCount = 100,
int maxHistoryRequests = 10,
String? sinceEventId,
int? limit,
bool Function(Event)? searchFunc,
}) async* {
assert(searchTerm != null || searchFunc != null);
searchFunc ??= (event) =>
event.body.toLowerCase().contains(searchTerm?.toLowerCase() ?? '');
final found = <Event>[];
if (sinceEventId == null) {
// Search locally
for (final event in events) {
if (searchFunc(event)) {
yield found..add(event);
}
}
// Search in database
var start = events.length;
while (true) {
final eventsFromStore = await room.client.database?.getEventList(
room,
start: start,
limit: requestHistoryCount,
) ??
[];
if (eventsFromStore.isEmpty) break;
start += eventsFromStore.length;
for (final event in eventsFromStore) {
if (searchFunc(event)) {
yield found..add(event);
}
}
}
}
// Search on the server
var prevBatch = room.prev_batch;
if (sinceEventId != null) {
prevBatch =
(await room.client.getEventContext(room.id, sinceEventId)).end;
}
final encryption = room.client.encryption;
for (var i = 0; i < maxHistoryRequests; i++) {
if (prevBatch == null) break;
if (limit != null && found.length >= limit) break;
try {
final resp = await room.client.getRoomEvents(
room.id,
Direction.b,
from: prevBatch,
limit: requestHistoryCount,
filter: jsonEncode(StateFilter(lazyLoadMembers: true).toJson()),
);
for (final sdnEvent in resp.chunk) {
var event = Event.fromSDNEvent(sdnEvent, room);
if (event.type == EventTypes.Encrypted && encryption != null) {
event = await encryption.decryptRoomEvent(room.id, event);
if (event.type == EventTypes.Encrypted &&
event.messageType == MessageTypes.BadEncrypted &&
event.content['can_request_session'] == true) {
// Await requestKey() here to ensure decrypted message bodies
await event.requestKey();
}
}
if (searchFunc(event)) {
yield found..add(event);
if (limit != null && found.length >= limit) break;
}
}
prevBatch = resp.end;
// We are at the beginning of the room
if (resp.chunk.length < requestHistoryCount) break;
} on SDNException catch (e) {
// We have no permission anymore to request the history
if (e.error == SDNError.M_FORBIDDEN) {
break;
}
rethrow;
}
}
return;
}