93 lines
3.0 KiB
JavaScript
93 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const { traceFunction } = require('../../tracing/trace-utilities');
|
|
|
|
const { DIRECTION } = require('matrix-public-archive-shared/lib/reference-values');
|
|
const timestampToEvent = require('./timestamp-to-event');
|
|
const getMessagesResponseFromEventId = require('./get-messages-response-from-event-id');
|
|
|
|
const config = require('../config');
|
|
const matrixServerUrl = config.get('matrixServerUrl');
|
|
assert(matrixServerUrl);
|
|
|
|
// Find an event right ahead of where we are trying to look. Then paginate
|
|
// /messages backwards. This makes sure that we can get events for the day when
|
|
// the room started. And it ensures that the `/messages` backfill kicks in
|
|
// properly since it only works to fill in the gaps going backwards.
|
|
//
|
|
// Consider this scenario: dayStart(fromTs) <- msg1 <- msg2 <- msg3 <- dayEnd(toTs)
|
|
// - ❌ If we start from dayStart and look backwards, we will find nothing.
|
|
// - ❌ If we start from dayStart and look forwards, we will find msg1, but
|
|
// federated backfill won't be able to paginate forwards
|
|
// - ✅ If we start from dayEnd and look backwards, we will find msg3 and
|
|
// federation backfill can paginate backwards
|
|
// - ❌ If we start from dayEnd and look forwards, we will find nothing
|
|
//
|
|
// Returns events in reverse-chronological order.
|
|
async function fetchEventsFromTimestampBackwards({ accessToken, roomId, ts, limit, abortSignal }) {
|
|
assert(accessToken);
|
|
assert(roomId);
|
|
assert(ts);
|
|
// Synapse has a max `/messages` limit of 1000
|
|
assert(
|
|
limit <= 1000,
|
|
'We can only get 1000 messages at a time from Synapse. If you need more messages, we will have to implement pagination'
|
|
);
|
|
|
|
let eventIdForTimestamp;
|
|
try {
|
|
const { eventId } = await timestampToEvent({
|
|
accessToken,
|
|
roomId,
|
|
ts,
|
|
direction: DIRECTION.backward,
|
|
abortSignal,
|
|
});
|
|
eventIdForTimestamp = eventId;
|
|
} catch (err) {
|
|
const allowedErrorCodes = [
|
|
// Allow `404: Unable to find event xxx in direction x`
|
|
// so we can just display an empty placeholder with no events.
|
|
404,
|
|
];
|
|
if (!allowedErrorCodes.includes(err?.response?.status)) {
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
if (!eventIdForTimestamp) {
|
|
return {
|
|
stateEventMap: {},
|
|
events: [],
|
|
};
|
|
}
|
|
|
|
const messageResData = await getMessagesResponseFromEventId({
|
|
accessToken,
|
|
roomId,
|
|
eventId: eventIdForTimestamp,
|
|
// We go backwards because that's the direction that backfills events (Synapse
|
|
// doesn't backfill in the forward direction)
|
|
dir: DIRECTION.backward,
|
|
limit,
|
|
abortSignal,
|
|
});
|
|
|
|
const stateEventMap = {};
|
|
for (const stateEvent of messageResData.state || []) {
|
|
if (stateEvent.type === 'm.room.member') {
|
|
stateEventMap[stateEvent.state_key] = stateEvent;
|
|
}
|
|
}
|
|
|
|
const chronologicalEvents = messageResData?.chunk?.reverse() || [];
|
|
|
|
return {
|
|
stateEventMap,
|
|
events: chronologicalEvents,
|
|
};
|
|
}
|
|
|
|
module.exports = traceFunction(fetchEventsFromTimestampBackwards);
|