You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-06 12:02:40 +03:00
Fix handling of remote echoes doubling up (#2639)
* Fix handling of remote echoes doubling up * Simplify code * Make TSC strict happier * Update `timelineWasEmpty` to match type * Add tests * Add tests * Add lowly `!`
This commit is contained in:
committed by
GitHub
parent
876491e38d
commit
8aee884d03
@@ -16,14 +16,15 @@ limitations under the License.
|
|||||||
|
|
||||||
import * as utils from "../test-utils/test-utils";
|
import * as utils from "../test-utils/test-utils";
|
||||||
import {
|
import {
|
||||||
|
DuplicateStrategy,
|
||||||
EventTimeline,
|
EventTimeline,
|
||||||
EventTimelineSet,
|
EventTimelineSet,
|
||||||
EventType,
|
EventType,
|
||||||
|
Filter,
|
||||||
MatrixClient,
|
MatrixClient,
|
||||||
MatrixEvent,
|
MatrixEvent,
|
||||||
MatrixEventEvent,
|
MatrixEventEvent,
|
||||||
Room,
|
Room,
|
||||||
DuplicateStrategy,
|
|
||||||
} from '../../src';
|
} from '../../src';
|
||||||
import { Thread } from "../../src/models/thread";
|
import { Thread } from "../../src/models/thread";
|
||||||
import { ReEmitter } from "../../src/ReEmitter";
|
import { ReEmitter } from "../../src/ReEmitter";
|
||||||
@@ -291,4 +292,34 @@ describe('EventTimelineSet', () => {
|
|||||||
expect(eventTimelineSet.canContain(event)).toBeTruthy();
|
expect(eventTimelineSet.canContain(event)).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("handleRemoteEcho", () => {
|
||||||
|
it("should add to liveTimeline only if the event matches the filter", () => {
|
||||||
|
const filter = new Filter(client.getUserId()!, "test_filter");
|
||||||
|
filter.setDefinition({
|
||||||
|
room: {
|
||||||
|
timeline: {
|
||||||
|
types: [EventType.RoomMessage],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const eventTimelineSet = new EventTimelineSet(room, { filter }, client);
|
||||||
|
|
||||||
|
const roomMessageEvent = new MatrixEvent({
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
content: { body: "test" },
|
||||||
|
event_id: "!test1:server",
|
||||||
|
});
|
||||||
|
eventTimelineSet.handleRemoteEcho(roomMessageEvent, "~!local-event-id:server", roomMessageEvent.getId());
|
||||||
|
expect(eventTimelineSet.getLiveTimeline().getEvents()).toContain(roomMessageEvent);
|
||||||
|
|
||||||
|
const roomFilteredEvent = new MatrixEvent({
|
||||||
|
type: "other_event_type",
|
||||||
|
content: { body: "test" },
|
||||||
|
event_id: "!test2:server",
|
||||||
|
});
|
||||||
|
eventTimelineSet.handleRemoteEcho(roomFilteredEvent, "~!local-event-id:server", roomFilteredEvent.getId());
|
||||||
|
expect(eventTimelineSet.getLiveTimeline().getEvents()).not.toContain(roomFilteredEvent);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -288,11 +288,11 @@ describe("Room", function() {
|
|||||||
room.addLiveEvents(events);
|
room.addLiveEvents(events);
|
||||||
expect(room.currentState.setStateEvents).toHaveBeenCalledWith(
|
expect(room.currentState.setStateEvents).toHaveBeenCalledWith(
|
||||||
[events[0]],
|
[events[0]],
|
||||||
{ timelineWasEmpty: undefined },
|
{ timelineWasEmpty: false },
|
||||||
);
|
);
|
||||||
expect(room.currentState.setStateEvents).toHaveBeenCalledWith(
|
expect(room.currentState.setStateEvents).toHaveBeenCalledWith(
|
||||||
[events[1]],
|
[events[1]],
|
||||||
{ timelineWasEmpty: undefined },
|
{ timelineWasEmpty: false },
|
||||||
);
|
);
|
||||||
expect(events[0].forwardLooking).toBe(true);
|
expect(events[0].forwardLooking).toBe(true);
|
||||||
expect(events[1].forwardLooking).toBe(true);
|
expect(events[1].forwardLooking).toBe(true);
|
||||||
@@ -426,6 +426,17 @@ describe("Room", function() {
|
|||||||
// but without the event ID matching we will still have the local event in pending events
|
// but without the event ID matching we will still have the local event in pending events
|
||||||
expect(room.getEventForTxnId(txnId)).toBeUndefined();
|
expect(room.getEventForTxnId(txnId)).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should correctly handle remote echoes from other devices", () => {
|
||||||
|
const remoteEvent = utils.mkMessage({
|
||||||
|
room: roomId, user: userA, event: true,
|
||||||
|
});
|
||||||
|
remoteEvent.event.unsigned = { transaction_id: "TXN_ID" };
|
||||||
|
|
||||||
|
// add the remoteEvent
|
||||||
|
room.addLiveEvents([remoteEvent]);
|
||||||
|
expect(room.timeline.length).toEqual(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('addEphemeralEvents', () => {
|
describe('addEphemeralEvents', () => {
|
||||||
|
@@ -729,18 +729,10 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
if (existingTimeline) {
|
if (existingTimeline) {
|
||||||
this._eventIdToTimeline.delete(oldEventId);
|
this._eventIdToTimeline.delete(oldEventId);
|
||||||
this._eventIdToTimeline.set(newEventId, existingTimeline);
|
this._eventIdToTimeline.set(newEventId, existingTimeline);
|
||||||
} else {
|
} else if (!this.filter || this.filter.filterRoomTimeline([localEvent]).length) {
|
||||||
if (this.filter) {
|
this.addEventToTimeline(localEvent, this.liveTimeline, {
|
||||||
if (this.filter.filterRoomTimeline([localEvent]).length) {
|
toStartOfTimeline: false,
|
||||||
this.addEventToTimeline(localEvent, this.liveTimeline, {
|
});
|
||||||
toStartOfTimeline: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.addEventToTimeline(localEvent, this.liveTimeline, {
|
|
||||||
toStartOfTimeline: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1981,14 +1981,6 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getUnsigned().transaction_id) {
|
|
||||||
const existingEvent = this.txnToEvent[event.getUnsigned().transaction_id];
|
|
||||||
if (existingEvent) {
|
|
||||||
// remote echo of an event we sent earlier
|
|
||||||
this.handleRemoteEcho(event, existingEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1996,7 +1988,7 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
|
|||||||
* "Room.timeline".
|
* "Room.timeline".
|
||||||
*
|
*
|
||||||
* @param {MatrixEvent} event Event to be added
|
* @param {MatrixEvent} event Event to be added
|
||||||
* @param {IAddLiveEventOptions} options addLiveEvent options
|
* @param {IAddLiveEventOptions} addLiveEventOptions addLiveEvent options
|
||||||
* @fires module:client~MatrixClient#event:"Room.timeline"
|
* @fires module:client~MatrixClient#event:"Room.timeline"
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -2344,7 +2336,7 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
|
|||||||
fromCache = false,
|
fromCache = false,
|
||||||
): void {
|
): void {
|
||||||
let duplicateStrategy = duplicateStrategyOrOpts as DuplicateStrategy;
|
let duplicateStrategy = duplicateStrategyOrOpts as DuplicateStrategy;
|
||||||
let timelineWasEmpty: boolean;
|
let timelineWasEmpty = false;
|
||||||
if (typeof (duplicateStrategyOrOpts) === 'object') {
|
if (typeof (duplicateStrategyOrOpts) === 'object') {
|
||||||
({
|
({
|
||||||
duplicateStrategy,
|
duplicateStrategy,
|
||||||
@@ -2383,10 +2375,25 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
|
|||||||
const threadRoots = this.findThreadRoots(events);
|
const threadRoots = this.findThreadRoots(events);
|
||||||
const eventsByThread: { [threadId: string]: MatrixEvent[] } = {};
|
const eventsByThread: { [threadId: string]: MatrixEvent[] } = {};
|
||||||
|
|
||||||
|
const options: IAddLiveEventOptions = {
|
||||||
|
duplicateStrategy,
|
||||||
|
fromCache,
|
||||||
|
timelineWasEmpty,
|
||||||
|
};
|
||||||
|
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
// TODO: We should have a filter to say "only add state event types X Y Z to the timeline".
|
// TODO: We should have a filter to say "only add state event types X Y Z to the timeline".
|
||||||
this.processLiveEvent(event);
|
this.processLiveEvent(event);
|
||||||
|
|
||||||
|
if (event.getUnsigned().transaction_id) {
|
||||||
|
const existingEvent = this.txnToEvent[event.getUnsigned().transaction_id!];
|
||||||
|
if (existingEvent) {
|
||||||
|
// remote echo of an event we sent earlier
|
||||||
|
this.handleRemoteEcho(event, existingEvent);
|
||||||
|
continue; // we can skip adding the event to the timeline sets, it is already there
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
shouldLiveInRoom,
|
shouldLiveInRoom,
|
||||||
shouldLiveInThread,
|
shouldLiveInThread,
|
||||||
@@ -2399,11 +2406,7 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
|
|||||||
eventsByThread[threadId]?.push(event);
|
eventsByThread[threadId]?.push(event);
|
||||||
|
|
||||||
if (shouldLiveInRoom) {
|
if (shouldLiveInRoom) {
|
||||||
this.addLiveEvent(event, {
|
this.addLiveEvent(event, options);
|
||||||
duplicateStrategy,
|
|
||||||
fromCache,
|
|
||||||
timelineWasEmpty,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user