Use fetchRelations to backfill.

This commit is contained in:
Half-Shot
2024-11-12 17:02:04 +00:00
parent a62e884e8c
commit 3b272181ae
2 changed files with 35 additions and 44 deletions

View File

@@ -11,8 +11,6 @@ import {
RelationType, RelationType,
RoomEvent as MatrixRoomEvent, RoomEvent as MatrixRoomEvent,
MatrixEventEvent, MatrixEventEvent,
ClientEvent,
SyncState,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { ReactionEventContent } from "matrix-js-sdk/src/types"; import { ReactionEventContent } from "matrix-js-sdk/src/types";
import { import {
@@ -93,7 +91,6 @@ export const ReactionsProvider = ({
clientState?.state === "valid" && clientState.supportedFeatures.reactions; clientState?.state === "valid" && clientState.supportedFeatures.reactions;
const room = rtcSession.room; const room = rtcSession.room;
const myUserId = room.client.getUserId(); const myUserId = room.client.getUserId();
const [hasBackfilled, setHasBackfilled] = useState(false);
const [reactions, setReactions] = useState<Record<string, ReactionOption>>( const [reactions, setReactions] = useState<Record<string, ReactionOption>>(
{}, {},
@@ -124,19 +121,29 @@ export const ReactionsProvider = ({
}, []); }, []);
// This effect will check the state whenever the membership of the session changes. // This effect will check the state whenever the membership of the session changes.
// This function is safe to run multiple times. useEffect(() => {
const backfillHandRaised = useCallback(() => {
// Fetches the first reaction for a given event. // Fetches the first reaction for a given event.
const getLastReactionEvent = ( const getLastReactionEvent = async (
eventId: string, eventId: string,
expectedSender: string, expectedSender: string,
): MatrixEvent | undefined => { ): Promise<MatrixEvent | undefined> => {
const relations = room.relations.getChildEventsForEvent( const relations = room.relations.getChildEventsForEvent(
eventId, eventId,
RelationType.Annotation, RelationType.Annotation,
EventType.Reaction, EventType.Reaction,
); );
const allEvents = relations?.getRelations() ?? []; let allEvents = relations?.getRelations() ?? [];
// We might not have synced this far.
if (allEvents.length === 0) {
const res = await room.client.fetchRelations(
room.roomId,
eventId,
RelationType.Annotation,
EventType.Reaction,
);
allEvents = res.chunk.map((e) => new MatrixEvent(e));
}
return allEvents.find( return allEvents.find(
(reaction) => (reaction) =>
reaction.event.sender === expectedSender && reaction.event.sender === expectedSender &&
@@ -166,47 +173,32 @@ export const ReactionsProvider = ({
// was raised, reset. // was raised, reset.
removeRaisedHand(m.sender); removeRaisedHand(m.sender);
} }
const reaction = getLastReactionEvent(m.eventId, m.sender); getLastReactionEvent(m.eventId, m.sender)
if (reaction) { .then((reaction) => {
const eventId = reaction?.getId(); if (reaction) {
if (!eventId) { const eventId = reaction.getId();
continue; if (!eventId) {
} return;
addRaisedHand(m.sender, { }
membershipEventId: m.eventId, addRaisedHand(m.sender!, {
reactionEventId: eventId, membershipEventId: m.eventId!,
time: new Date(reaction.localTimestamp), reactionEventId: eventId,
time: new Date(reaction.localTimestamp),
});
}
})
.catch((ex) => {
logger.warn(
`Failed to fetch reaction for member ${m.sender} (${m.eventId})`,
ex,
);
}); });
}
} }
// Ignoring raisedHands here because we don't want to trigger each time the raised // Ignoring raisedHands here because we don't want to trigger each time the raised
// hands set is updated. // hands set is updated.
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [room, memberships, myUserId, addRaisedHand, removeRaisedHand]); }, [room, memberships, myUserId, addRaisedHand, removeRaisedHand]);
useEffect(() => {
// Run once on startup (and will rerun when membership changes above)
backfillHandRaised();
function onSync(state: SyncState | null): void {
if (state === SyncState.Prepared) {
logger.debug("Backfilling hand raised after successful sync.");
backfillHandRaised();
setHasBackfilled(true);
}
}
// The *first* time we successfully sync, fetch reactions as they may not
// be immediately available.
if (!hasBackfilled) {
room.client.on(ClientEvent.Sync, onSync);
}
return (): void => {
if (!hasBackfilled) {
room.client.off(ClientEvent.Sync, onSync);
}
};
}, [backfillHandRaised, room, hasBackfilled]);
const latestMemberships = useLatest(memberships); const latestMemberships = useLatest(memberships);
const latestRaisedHands = useLatest(raisedHands); const latestRaisedHands = useLatest(raisedHands);
@@ -348,8 +340,6 @@ export const ReactionsProvider = ({
removeRaisedHand, removeRaisedHand,
latestMemberships, latestMemberships,
latestRaisedHands, latestRaisedHands,
backfillHandRaised,
hasBackfilled,
]); ]);
const lowerHand = useCallback(async () => { const lowerHand = useCallback(async () => {

View File

@@ -139,6 +139,7 @@ export class MockRoom extends EventEmitter {
return Promise.resolve({ event_id: randomUUID() }); return Promise.resolve({ event_id: randomUUID() });
}, },
decryptEventIfNeeded: async () => {}, decryptEventIfNeeded: async () => {},
fetchRelations: async () => Promise.resolve({ chunk: [] }),
on() { on() {
return this; return this;
}, },