diff --git a/syncapi/routing/messages.go b/syncapi/routing/messages.go index 6905e25c7..ac337f60d 100644 --- a/syncapi/routing/messages.go +++ b/syncapi/routing/messages.go @@ -336,7 +336,15 @@ func (r *messagesReq) retrieveEvents(ctx context.Context, rsAPI api.SyncRoomserv // removed all of them. This means there are no events for this user // anymore. Let them know. if errors.Is(err, shared.ErrNoEventsForFilter) { - return []synctypes.ClientEvent{}, *r.from, emptyToken, nil + if len(streamEvents) == 0 { + return []synctypes.ClientEvent{}, *r.from, emptyToken, nil + } + // We possibly received events, try to get start/end from them + start, end, err = r.getStartEnd(r.snapshot.StreamEventsToEvents(ctx, r.device, streamEvents, rsAPI)) + if err != nil { + return []synctypes.ClientEvent{}, *r.from, *r.to, err + } + return []synctypes.ClientEvent{}, start, end, nil } err = fmt.Errorf("GetEventsInRange: %w", err) return []synctypes.ClientEvent{}, *r.from, emptyToken, err diff --git a/syncapi/storage/interface.go b/syncapi/storage/interface.go index 243b2592a..913049e83 100644 --- a/syncapi/storage/interface.go +++ b/syncapi/storage/interface.go @@ -81,7 +81,10 @@ type DatabaseTransaction interface { // If no data is retrieved, returns an empty map // If there was an issue with the retrieval, returns an error GetAccountDataInRange(ctx context.Context, userID string, r types.Range, accountDataFilterPart *synctypes.EventFilter) (map[string][]string, types.StreamPosition, error) - // GetEventsInTopologicalRange retrieves all of the events on a given ordering using the given extremities and limit. If backwardsOrdering is true, the most recent event must be first, else last. + // GetEventsInTopologicalRange retrieves all of the events on a given ordering using the given extremities and limit. + // If backwardsOrdering is true, the most recent event must be first, else last. + // Returns the filtered StreamEvents on success. Returns **unfiltered** StreamEvents and ErrNoEventsForFilter if + // the provided filter removed all events, this can be used to still calculate the start/end position. (e.g for `/messages`) GetEventsInTopologicalRange(ctx context.Context, from, to *types.TopologyToken, roomID string, filter *synctypes.RoomEventFilter, backwardOrdering bool) (events []types.StreamEvent, err error) // EventPositionInTopology returns the depth and stream position of the given event. EventPositionInTopology(ctx context.Context, eventID string) (types.TopologyToken, error) diff --git a/syncapi/storage/shared/storage_sync.go b/syncapi/storage/shared/storage_sync.go index 478e9a533..ddfd2465c 100644 --- a/syncapi/storage/shared/storage_sync.go +++ b/syncapi/storage/shared/storage_sync.go @@ -273,7 +273,13 @@ func (d *DatabaseTransaction) GetEventsInTopologicalRange( // Check if we should be able to return events. // If we received 0 events, this most likely means that the provided filter removed them. if len(eIDs) > 0 && len(events) == 0 { - return nil, ErrNoEventsForFilter + // We try to fetch the events without a filter, so we can tell the client if there + // are more events earlier than the requested and filtered. + events, err = d.OutputEvents.SelectEvents(ctx, d.txn, eIDs, nil, true) + if err != nil { + return + } + return events, ErrNoEventsForFilter } return diff --git a/syncapi/storage/storage_test.go b/syncapi/storage/storage_test.go index a4eb9412a..26f661aff 100644 --- a/syncapi/storage/storage_test.go +++ b/syncapi/storage/storage_test.go @@ -250,7 +250,8 @@ func TestGetEventsInRangeWithTopologyTokenNoEventsForFilter(t *testing.T) { filter := &synctypes.RoomEventFilter{Limit: 20, NotTypes: ¬Types, Senders: &senders} paginatedEvents, err := snapshot.GetEventsInTopologicalRange(ctx, &from, &to, r.ID, filter, true) assert.Equal(t, shared.ErrNoEventsForFilter, err) - assert.Nil(t, paginatedEvents) + gots := snapshot.StreamEventsToEvents(context.Background(), nil, paginatedEvents, nil) + test.AssertEventsEqual(t, gots, test.Reversed(events[len(events)-15:])) }) }) }