Don't send prehistorical events to widgets during decryption at startup
Fixes https://github.com/vector-im/element-web/issues/18060 Tracking a localized read receipt of sorts appears to be the fastest and least complex approach, though not the greatest.
This commit is contained in:
parent
470bc0ffe7
commit
20b6219121
1 changed files with 47 additions and 0 deletions
|
@ -55,6 +55,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { ELEMENT_CLIENT_ID } from "../../identifiers";
|
import { ELEMENT_CLIENT_ID } from "../../identifiers";
|
||||||
import { getUserLanguage } from "../../languageHandler";
|
import { getUserLanguage } from "../../languageHandler";
|
||||||
import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables";
|
import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables";
|
||||||
|
import { arrayFastClone } from "../../utils/arrays";
|
||||||
|
|
||||||
// TODO: Destroy all of this code
|
// TODO: Destroy all of this code
|
||||||
|
|
||||||
|
@ -146,6 +147,7 @@ export class StopGapWidget extends EventEmitter {
|
||||||
private scalarToken: string;
|
private scalarToken: string;
|
||||||
private roomId?: string;
|
private roomId?: string;
|
||||||
private kind: WidgetKind;
|
private kind: WidgetKind;
|
||||||
|
private readUpToMap: {[roomId: string]: string} = {}; // room ID to event ID
|
||||||
|
|
||||||
constructor(private appTileProps: IAppTileProps) {
|
constructor(private appTileProps: IAppTileProps) {
|
||||||
super();
|
super();
|
||||||
|
@ -294,6 +296,14 @@ export class StopGapWidget extends EventEmitter {
|
||||||
this.messaging.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
|
this.messaging.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Populate the map of "read up to" events for this widget with the current event in every room.
|
||||||
|
// This is a bit inefficient, but should be okay. We do this for all rooms in case the widget
|
||||||
|
// requests timeline capabilities in other rooms down the road. It's just easier to manage here.
|
||||||
|
for (const room of MatrixClientPeg.get().getRooms()) {
|
||||||
|
// Timelines are most recent last
|
||||||
|
this.readUpToMap[room.roomId] = arrayFastClone(room.getLiveTimeline().getEvents()).reverse()[0].getId();
|
||||||
|
}
|
||||||
|
|
||||||
// Attach listeners for feeding events - the underlying widget classes handle permissions for us
|
// Attach listeners for feeding events - the underlying widget classes handle permissions for us
|
||||||
MatrixClientPeg.get().on('event', this.onEvent);
|
MatrixClientPeg.get().on('event', this.onEvent);
|
||||||
MatrixClientPeg.get().on('Event.decrypted', this.onEventDecrypted);
|
MatrixClientPeg.get().on('Event.decrypted', this.onEventDecrypted);
|
||||||
|
@ -421,6 +431,43 @@ export class StopGapWidget extends EventEmitter {
|
||||||
private feedEvent(ev: MatrixEvent) {
|
private feedEvent(ev: MatrixEvent) {
|
||||||
if (!this.messaging) return;
|
if (!this.messaging) return;
|
||||||
|
|
||||||
|
// Check to see if this event would be before or after our "read up to" marker. If it's
|
||||||
|
// before, or we can't decide, then we assume the widget will have already seen the event.
|
||||||
|
// If the event is after, or we don't have a marker for the room, then we'll send it through.
|
||||||
|
//
|
||||||
|
// This approach of "read up to" prevents widgets receiving decryption spam from startup or
|
||||||
|
// receiving out-of-order events from backfill and such.
|
||||||
|
const upToEventId = this.readUpToMap[ev.getRoomId()];
|
||||||
|
if (upToEventId) {
|
||||||
|
// Small optimization for exact match (prevent search)
|
||||||
|
if (upToEventId === ev.getId()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isBeforeMark = true;
|
||||||
|
|
||||||
|
// Timelines are most recent last, so reverse the order and limit ourselves to 100 events
|
||||||
|
// to avoid overusing the CPU.
|
||||||
|
const timeline = MatrixClientPeg.get().getRoom(ev.getRoomId()).getLiveTimeline();
|
||||||
|
const events = arrayFastClone(timeline.getEvents()).reverse().slice(0, 100);
|
||||||
|
|
||||||
|
for (const timelineEvent of events) {
|
||||||
|
if (timelineEvent.getId() === upToEventId) {
|
||||||
|
break;
|
||||||
|
} else if (timelineEvent.getId() === ev.getId()) {
|
||||||
|
isBeforeMark = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBeforeMark) {
|
||||||
|
// Ignore the event: it is before our interest.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.readUpToMap[ev.getRoomId()] = ev.getId();
|
||||||
|
|
||||||
const raw = ev.getEffectiveEvent();
|
const raw = ev.getEffectiveEvent();
|
||||||
this.messaging.feedEvent(raw).catch(e => {
|
this.messaging.feedEvent(raw).catch(e => {
|
||||||
console.error("Error sending event to widget: ", e);
|
console.error("Error sending event to widget: ", e);
|
||||||
|
|
Loading…
Reference in a new issue