Skip to content

Commit aaabff0

Browse files
committed
Remove need to call /initialSync in getMessagesByUserIn.
Technically still unstable https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3roomsroomidmessages matrix-org/matrix-spec#1002 Synapse has supported this for over 2 years and Element web depends on it for threads. matrix-org/matrix-js-sdk#2065 Given that redactions are super heavy in Mjolnir already and have been reported as barely functional on matrix.org I believe we should also adopt this approach as if for some reason Synapse did change before the next release (extremely unlikely) we can revert this commit.
1 parent bcc3405 commit aaabff0

File tree

1 file changed

+23
-44
lines changed

1 file changed

+23
-44
lines changed

src/utils.ts

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -121,29 +121,16 @@ export async function getMessagesByUserIn(client: MatrixClient, sender: string,
121121
}
122122
}
123123

124-
/**
125-
* Note: `rooms/initialSync` is deprecated. However, there is no replacement for this API for the time being.
126-
* While previous versions of this function used `/sync`, experience shows that it can grow extremely
127-
* slow (4-5 minutes long) when we need to sync many large rooms, which leads to timeouts and
128-
* breakage in Mjolnir, see https://github.com/matrix-org/synapse/issues/10842.
129-
*/
130-
function roomInitialSync() {
131-
return client.doRequest("GET", `/_matrix/client/r0/rooms/${encodeURIComponent(roomId)}/initialSync`);
132-
}
133-
134-
function backfill(from: string) {
124+
function backfill(from: string|null) {
135125
const qs = {
136126
filter: JSON.stringify(roomEventFilter),
137-
from: from,
138127
dir: "b",
128+
... from ? { from } : {}
139129
};
140130
LogService.info("utils", "Backfilling with token: " + from);
141-
return client.doRequest("GET", `/_matrix/client/r0/rooms/${encodeURIComponent(roomId)}/messages`, qs);
131+
return client.doRequest("GET", `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/messages`, qs);
142132
}
143133

144-
// Do an initial sync first to get the batch token
145-
const response = await roomInitialSync();
146-
147134
let processed = 0;
148135
/**
149136
* Filter events from the timeline to events that are from a matching sender and under the limit that can be processed by the callback.
@@ -160,35 +147,27 @@ export async function getMessagesByUserIn(client: MatrixClient, sender: string,
160147
}
161148
return messages;
162149
}
163-
164-
// The recommended APIs for fetching events from a room is to use both rooms/initialSync then /messages.
165-
// Unfortunately, this results in code that is rather hard to read, as these two APIs employ very different data structures.
166-
// We prefer discarding the results from rooms/initialSync and reading only from /messages,
167-
// even if it's a little slower, for the sake of code maintenance.
168-
const timeline = response['messages']
169-
if (timeline) {
170-
// The end of the PaginationChunk has the most recent events from rooms/initialSync.
171-
// This token is required be present in the PagintionChunk from rooms/initialSync.
172-
let token = timeline['end']!;
173-
// We check that we have the token because rooms/messages is not required to provide one
174-
// and will not provide one when there is no more history to paginate.
175-
while (token && processed < limit) {
176-
const bfMessages = await backfill(token);
177-
let lastToken = token;
178-
token = bfMessages['end'];
179-
if (lastToken === token) {
180-
LogService.debug("utils", "Backfill returned same end token - returning early.");
181-
return;
182-
}
183-
const events = filterEvents(bfMessages['chunk'] || []);
184-
// If we are using a glob, there may be no relevant events in this chunk.
185-
if (events.length > 0) {
186-
await cb(events);
187-
}
150+
// We check that we have the token because rooms/messages is not required to provide one
151+
// and will not provide one when there is no more history to paginate.
152+
let token: string|null = null;
153+
do {
154+
const bfMessages: { chunk: any[], end?: string } = await backfill(token);
155+
const lastToken: string|null = token;
156+
token = bfMessages['end'] ?? null;
157+
const events = filterEvents(bfMessages['chunk'] || []);
158+
// If we are using a glob, there may be no relevant events in this chunk.
159+
if (events.length > 0) {
160+
await cb(events);
188161
}
189-
} else {
190-
throw new Error(`Internal Error: rooms/initialSync did not return a pagination chunk for ${roomId}, this is not normal and if it is we need to stop using it. See roomInitialSync() for why we are using it.`);
191-
}
162+
// This check exists only becuase of a Synapse compliance bug https://github.com/matrix-org/synapse/issues/12102.
163+
// We also check after processing events as the `lastToken` can be 'null' if we are at the start of the steam
164+
// and `token` can also be 'null' as we have paginated the entire timeline, but there would be unprocessed events in the
165+
// chunk that was returned in this request.
166+
if (lastToken === token) {
167+
LogService.debug("utils", "Backfill returned same end token - returning early.");
168+
return;
169+
}
170+
} while (token && processed < limit)
192171
}
193172

194173
/*

0 commit comments

Comments
 (0)