You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-25 05:23:13 +03:00
Improve thread partitioning for 2nd degree relations (#2165)
This commit is contained in:
@@ -3,7 +3,6 @@ import { CRYPTO_ENABLED } from "../../src/client";
|
|||||||
import { MatrixEvent } from "../../src/models/event";
|
import { MatrixEvent } from "../../src/models/event";
|
||||||
import { Filter, MemoryStore, Room } from "../../src/matrix";
|
import { Filter, MemoryStore, Room } from "../../src/matrix";
|
||||||
import { TestClient } from "../TestClient";
|
import { TestClient } from "../TestClient";
|
||||||
import { Thread } from "../../src/models/thread";
|
|
||||||
|
|
||||||
describe("MatrixClient", function() {
|
describe("MatrixClient", function() {
|
||||||
let client = null;
|
let client = null;
|
||||||
@@ -405,6 +404,11 @@ describe("MatrixClient", function() {
|
|||||||
|
|
||||||
it("copies pre-thread in-timeline vote events onto both timelines", function() {
|
it("copies pre-thread in-timeline vote events onto both timelines", function() {
|
||||||
client.clientOpts = { experimentalThreadSupport: true };
|
client.clientOpts = { experimentalThreadSupport: true };
|
||||||
|
|
||||||
|
const eventMessageInThread = buildEventMessageInThread();
|
||||||
|
const eventPollResponseReference = buildEventPollResponseReference();
|
||||||
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
||||||
|
|
||||||
const events = [
|
const events = [
|
||||||
eventMessageInThread,
|
eventMessageInThread,
|
||||||
eventPollResponseReference,
|
eventPollResponseReference,
|
||||||
@@ -435,6 +439,11 @@ describe("MatrixClient", function() {
|
|||||||
|
|
||||||
it("copies pre-thread in-timeline reactions onto both timelines", function() {
|
it("copies pre-thread in-timeline reactions onto both timelines", function() {
|
||||||
client.clientOpts = { experimentalThreadSupport: true };
|
client.clientOpts = { experimentalThreadSupport: true };
|
||||||
|
|
||||||
|
const eventMessageInThread = buildEventMessageInThread();
|
||||||
|
const eventReaction = buildEventReaction();
|
||||||
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
||||||
|
|
||||||
const events = [
|
const events = [
|
||||||
eventMessageInThread,
|
eventMessageInThread,
|
||||||
eventReaction,
|
eventReaction,
|
||||||
@@ -456,6 +465,11 @@ describe("MatrixClient", function() {
|
|||||||
|
|
||||||
it("copies post-thread in-timeline vote events onto both timelines", function() {
|
it("copies post-thread in-timeline vote events onto both timelines", function() {
|
||||||
client.clientOpts = { experimentalThreadSupport: true };
|
client.clientOpts = { experimentalThreadSupport: true };
|
||||||
|
|
||||||
|
const eventPollResponseReference = buildEventPollResponseReference();
|
||||||
|
const eventMessageInThread = buildEventMessageInThread();
|
||||||
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
||||||
|
|
||||||
const events = [
|
const events = [
|
||||||
eventPollResponseReference,
|
eventPollResponseReference,
|
||||||
eventMessageInThread,
|
eventMessageInThread,
|
||||||
@@ -475,119 +489,13 @@ describe("MatrixClient", function() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("copies post-thread in-thread vote events onto both timelines", function() {
|
|
||||||
client.clientOpts = { experimentalThreadSupport: true };
|
|
||||||
|
|
||||||
// Events for this test only, because we hack around with them
|
|
||||||
const eventMessageInThread2 = new MatrixEvent({
|
|
||||||
"age": 80098509,
|
|
||||||
"content": {
|
|
||||||
"algorithm": "m.megolm.v1.aes-sha2",
|
|
||||||
"ciphertext": "ENCRYPTEDSTUFF",
|
|
||||||
"device_id": "XISFUZSKHH",
|
|
||||||
"m.relates_to": {
|
|
||||||
"event_id": "$AAA2ojbPmxb6x8ECetn45hmND6cRDcjgv-j-to9m7Vo",
|
|
||||||
"m.in_reply_to": {
|
|
||||||
"event_id": "$AAA2ojbPmxb6x8ECetn45hmND6cRDcjgv-j-to9m7Vo",
|
|
||||||
},
|
|
||||||
"rel_type": "io.element.thread",
|
|
||||||
},
|
|
||||||
"sender_key": "i3N3CtG/CD2bGB8rA9fW6adLYSDvlUhf2iuU73L65Vg",
|
|
||||||
"session_id": "Ja11R/KG6ua0wdk8zAzognrxjio1Gm/RK2Gn6lFL804",
|
|
||||||
},
|
|
||||||
"event_id": "$AAAhKIGYowtBblVLkRimeIg8TcdjETnxhDPGfi6NpDg",
|
|
||||||
"origin_server_ts": 1643815466378,
|
|
||||||
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
||||||
"sender": "@andybalaam-test1:matrix.org",
|
|
||||||
"type": "m.room.encrypted",
|
|
||||||
"unsigned": { "age": 80098509 },
|
|
||||||
"user_id": "@andybalaam-test1:matrix.org",
|
|
||||||
});
|
|
||||||
|
|
||||||
const eventPollStartThreadRoot2 = new MatrixEvent({
|
|
||||||
"age": 80108647,
|
|
||||||
"content": {
|
|
||||||
"algorithm": "m.megolm.v1.aes-sha2",
|
|
||||||
"ciphertext": "ENCRYPTEDSTUFF",
|
|
||||||
"device_id": "XISFUZSKHH",
|
|
||||||
"sender_key": "i3N3CtG/CD2bGB8rA9fW6adLYSDvlUhf2iuU73L65Vg",
|
|
||||||
"session_id": "Ja11R/KG6ua0wdk8zAzognrxjio1Gm/RK2Gn6lFL804",
|
|
||||||
},
|
|
||||||
"event_id": "$AAA2ojbPmxb6x8ECetn45hmND6cRDcjgv-j-to9m7Vo",
|
|
||||||
"origin_server_ts": 1643815456240,
|
|
||||||
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
||||||
"sender": "@andybalaam-test1:matrix.org",
|
|
||||||
"type": "m.room.encrypted",
|
|
||||||
"unsigned": { "age": 80108647 },
|
|
||||||
"user_id": "@andybalaam-test1:matrix.org",
|
|
||||||
});
|
|
||||||
|
|
||||||
const eventPollResponseReference2 = new MatrixEvent({
|
|
||||||
"age": 80098509,
|
|
||||||
"content": {
|
|
||||||
"algorithm": "m.megolm.v1.aes-sha2",
|
|
||||||
"ciphertext": "ENCRYPTEDSTUFF",
|
|
||||||
"device_id": "XISFUZSKHH",
|
|
||||||
"m.relates_to": {
|
|
||||||
"event_id": "$AAA2ojbPmxb6x8ECetn45hmND6cRDcjgv-j-to9m7Vo",
|
|
||||||
"rel_type": "m.reference",
|
|
||||||
},
|
|
||||||
"sender_key": "i3N3CtG/CD2bGB8rA9fW6adLYSDvlUhf2iuU73L65Vg",
|
|
||||||
"session_id": "Ja11R/KG6ua0wdk8zAzognrxjio1Gm/RK2Gn6lFL804",
|
|
||||||
},
|
|
||||||
"event_id": "$AAAvpezvsF0cKgav3g8W-uEVS4WkDHgxbJZvL3uMR1g",
|
|
||||||
"origin_server_ts": 1643815458650,
|
|
||||||
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
||||||
"sender": "@andybalaam-test1:matrix.org",
|
|
||||||
"type": "m.room.encrypted",
|
|
||||||
"unsigned": { "age": 80106237 },
|
|
||||||
"user_id": "@andybalaam-test1:matrix.org",
|
|
||||||
});
|
|
||||||
|
|
||||||
// When we react within a thread, sometimes the thread root
|
|
||||||
// has isThreadRelation === true, because thread is set on it,
|
|
||||||
// but threadId is not.
|
|
||||||
eventPollStartThreadRoot2.setThread(
|
|
||||||
new Thread(
|
|
||||||
eventPollStartThreadRoot2,
|
|
||||||
{
|
|
||||||
client,
|
|
||||||
room: new Room(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const events = [
|
|
||||||
eventPollResponseReference2,
|
|
||||||
eventMessageInThread2,
|
|
||||||
eventPollStartThreadRoot2,
|
|
||||||
];
|
|
||||||
|
|
||||||
const [timeline, threaded] = client.partitionThreadedEvents(events);
|
|
||||||
|
|
||||||
expect(timeline).toEqual([
|
|
||||||
eventPollResponseReference2,
|
|
||||||
// eventPollStartThreadRoot2,
|
|
||||||
// This is weird: by hacking the thread root to have an inconsistency
|
|
||||||
// between thread and threadId (which is what I have observed in the
|
|
||||||
// wild), we have persuaded the code that the thread root is actually
|
|
||||||
// within the thread, so it is not provided to the main timeline.
|
|
||||||
//
|
|
||||||
// This should go away when we fix this inconsistency. When that
|
|
||||||
// happens, we should probably delete this test.
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(threaded).toEqual([
|
|
||||||
withThreadId(
|
|
||||||
eventPollResponseReference2, eventPollStartThreadRoot2.getId(),
|
|
||||||
),
|
|
||||||
eventMessageInThread2,
|
|
||||||
eventPollStartThreadRoot2, // See note above for why this appears here.
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("copies post-thread in-timeline reactions onto both timelines", function() {
|
it("copies post-thread in-timeline reactions onto both timelines", function() {
|
||||||
client.clientOpts = { experimentalThreadSupport: true };
|
client.clientOpts = { experimentalThreadSupport: true };
|
||||||
|
|
||||||
|
const eventReaction = buildEventReaction();
|
||||||
|
const eventMessageInThread = buildEventMessageInThread();
|
||||||
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
||||||
|
|
||||||
const events = [
|
const events = [
|
||||||
eventReaction,
|
eventReaction,
|
||||||
eventMessageInThread,
|
eventMessageInThread,
|
||||||
@@ -610,6 +518,19 @@ describe("MatrixClient", function() {
|
|||||||
it("sends room state events to the main timeline only", function() {
|
it("sends room state events to the main timeline only", function() {
|
||||||
client.clientOpts = { experimentalThreadSupport: true };
|
client.clientOpts = { experimentalThreadSupport: true };
|
||||||
// This is based on recording the events in a real room:
|
// This is based on recording the events in a real room:
|
||||||
|
|
||||||
|
const eventMessageInThread = buildEventMessageInThread();
|
||||||
|
const eventPollResponseReference = buildEventPollResponseReference();
|
||||||
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
||||||
|
const eventRoomName = buildEventRoomName();
|
||||||
|
const eventEncryption = buildEventEncryption();
|
||||||
|
const eventGuestAccess = buildEventGuestAccess();
|
||||||
|
const eventHistoryVisibility = buildEventHistoryVisibility();
|
||||||
|
const eventJoinRules = buildEventJoinRules();
|
||||||
|
const eventPowerLevels = buildEventPowerLevels();
|
||||||
|
const eventMember = buildEventMember();
|
||||||
|
const eventCreate = buildEventCreate();
|
||||||
|
|
||||||
const events = [
|
const events = [
|
||||||
eventMessageInThread,
|
eventMessageInThread,
|
||||||
eventPollResponseReference,
|
eventPollResponseReference,
|
||||||
@@ -655,7 +576,7 @@ function withThreadId(event, newThreadId) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const eventMessageInThread = new MatrixEvent({
|
const buildEventMessageInThread = () => new MatrixEvent({
|
||||||
"age": 80098509,
|
"age": 80098509,
|
||||||
"content": {
|
"content": {
|
||||||
"algorithm": "m.megolm.v1.aes-sha2",
|
"algorithm": "m.megolm.v1.aes-sha2",
|
||||||
@@ -680,7 +601,7 @@ const eventMessageInThread = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventPollResponseReference = new MatrixEvent({
|
const buildEventPollResponseReference = () => new MatrixEvent({
|
||||||
"age": 80098509,
|
"age": 80098509,
|
||||||
"content": {
|
"content": {
|
||||||
"algorithm": "m.megolm.v1.aes-sha2",
|
"algorithm": "m.megolm.v1.aes-sha2",
|
||||||
@@ -702,7 +623,7 @@ const eventPollResponseReference = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventReaction = new MatrixEvent({
|
const buildEventReaction = () => new MatrixEvent({
|
||||||
"content": {
|
"content": {
|
||||||
"m.relates_to": {
|
"m.relates_to": {
|
||||||
"event_id": "$VLS2ojbPmxb6x8ECetn45hmND6cRDcjgv-j-to9m7Vo",
|
"event_id": "$VLS2ojbPmxb6x8ECetn45hmND6cRDcjgv-j-to9m7Vo",
|
||||||
@@ -721,7 +642,7 @@ const eventReaction = new MatrixEvent({
|
|||||||
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventPollStartThreadRoot = new MatrixEvent({
|
const buildEventPollStartThreadRoot = () => new MatrixEvent({
|
||||||
"age": 80108647,
|
"age": 80108647,
|
||||||
"content": {
|
"content": {
|
||||||
"algorithm": "m.megolm.v1.aes-sha2",
|
"algorithm": "m.megolm.v1.aes-sha2",
|
||||||
@@ -739,7 +660,7 @@ const eventPollStartThreadRoot = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventRoomName = new MatrixEvent({
|
const buildEventRoomName = () => new MatrixEvent({
|
||||||
"age": 80123249,
|
"age": 80123249,
|
||||||
"content": {
|
"content": {
|
||||||
"name": "1 poll, 1 vote, 1 thread",
|
"name": "1 poll, 1 vote, 1 thread",
|
||||||
@@ -754,7 +675,7 @@ const eventRoomName = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventEncryption = new MatrixEvent({
|
const buildEventEncryption = () => new MatrixEvent({
|
||||||
"age": 80123383,
|
"age": 80123383,
|
||||||
"content": {
|
"content": {
|
||||||
"algorithm": "m.megolm.v1.aes-sha2",
|
"algorithm": "m.megolm.v1.aes-sha2",
|
||||||
@@ -769,7 +690,7 @@ const eventEncryption = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventGuestAccess = new MatrixEvent({
|
const buildEventGuestAccess = () => new MatrixEvent({
|
||||||
"age": 80123473,
|
"age": 80123473,
|
||||||
"content": {
|
"content": {
|
||||||
"guest_access": "can_join",
|
"guest_access": "can_join",
|
||||||
@@ -784,7 +705,7 @@ const eventGuestAccess = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventHistoryVisibility = new MatrixEvent({
|
const buildEventHistoryVisibility = () => new MatrixEvent({
|
||||||
"age": 80123556,
|
"age": 80123556,
|
||||||
"content": {
|
"content": {
|
||||||
"history_visibility": "shared",
|
"history_visibility": "shared",
|
||||||
@@ -799,7 +720,7 @@ const eventHistoryVisibility = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventJoinRules = new MatrixEvent({
|
const buildEventJoinRules = () => new MatrixEvent({
|
||||||
"age": 80123696,
|
"age": 80123696,
|
||||||
"content": {
|
"content": {
|
||||||
"join_rule": "invite",
|
"join_rule": "invite",
|
||||||
@@ -814,7 +735,7 @@ const eventJoinRules = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventPowerLevels = new MatrixEvent({
|
const buildEventPowerLevels = () => new MatrixEvent({
|
||||||
"age": 80124105,
|
"age": 80124105,
|
||||||
"content": {
|
"content": {
|
||||||
"ban": 50,
|
"ban": 50,
|
||||||
@@ -849,7 +770,7 @@ const eventPowerLevels = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventMember = new MatrixEvent({
|
const buildEventMember = () => new MatrixEvent({
|
||||||
"age": 80125279,
|
"age": 80125279,
|
||||||
"content": {
|
"content": {
|
||||||
"avatar_url": "mxc://matrix.org/aNtbVcFfwotudypZcHsIcPOc",
|
"avatar_url": "mxc://matrix.org/aNtbVcFfwotudypZcHsIcPOc",
|
||||||
@@ -866,7 +787,7 @@ const eventMember = new MatrixEvent({
|
|||||||
"user_id": "@andybalaam-test1:matrix.org",
|
"user_id": "@andybalaam-test1:matrix.org",
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventCreate = new MatrixEvent({
|
const buildEventCreate = () => new MatrixEvent({
|
||||||
"age": 80126105,
|
"age": 80126105,
|
||||||
"content": {
|
"content": {
|
||||||
"creator": "@andybalaam-test1:matrix.org",
|
"creator": "@andybalaam-test1:matrix.org",
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ export enum EventType {
|
|||||||
export enum RelationType {
|
export enum RelationType {
|
||||||
Annotation = "m.annotation",
|
Annotation = "m.annotation",
|
||||||
Replace = "m.replace",
|
Replace = "m.replace",
|
||||||
|
Reference = "m.reference",
|
||||||
/**
|
/**
|
||||||
* Note, "io.element.thread" is hardcoded
|
* Note, "io.element.thread" is hardcoded
|
||||||
* Should be replaced with "m.thread" once MSC3440 lands
|
* Should be replaced with "m.thread" once MSC3440 lands
|
||||||
|
|||||||
@@ -3594,17 +3594,20 @@ export class MatrixClient extends EventEmitter {
|
|||||||
threadId = null;
|
threadId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadId && content["m.relates_to"]?.rel_type !== RelationType.Thread) {
|
// If we expect that an event is part of a thread but is missing the relation
|
||||||
|
// we need to add it manually, as well as the reply fallback
|
||||||
|
if (threadId && !content["m.relates_to"]?.rel_type) {
|
||||||
content["m.relates_to"] = {
|
content["m.relates_to"] = {
|
||||||
...content["m.relates_to"],
|
...content["m.relates_to"],
|
||||||
"rel_type": RelationType.Thread,
|
"rel_type": RelationType.Thread,
|
||||||
"event_id": threadId,
|
"event_id": threadId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const thread = this.getRoom(roomId)?.threads.get(threadId);
|
const thread = this.getRoom(roomId)?.threads.get(threadId);
|
||||||
if (thread) {
|
if (thread) {
|
||||||
content["m.relates_to"]["m.in_reply_to"] = {
|
content["m.relates_to"]["m.in_reply_to"] = {
|
||||||
"event_id": thread.replyToEvent.getId(),
|
"event_id": thread.lastReply((ev: MatrixEvent) => {
|
||||||
|
return ev.isThreadRelation && !ev.status;
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3652,6 +3655,7 @@ export class MatrixClient extends EventEmitter {
|
|||||||
const thread = room?.threads.get(threadId);
|
const thread = room?.threads.get(threadId);
|
||||||
if (thread) {
|
if (thread) {
|
||||||
localEvent.setThread(thread);
|
localEvent.setThread(thread);
|
||||||
|
localEvent.setThreadId(thread.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is a relation or redaction of an event
|
// if this is a relation or redaction of an event
|
||||||
@@ -9089,6 +9093,52 @@ export class MatrixClient extends EventEmitter {
|
|||||||
return threadRoots;
|
return threadRoots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private eventShouldLiveIn(event: MatrixEvent, room: Room, events: MatrixEvent[], roots: Set<string>): {
|
||||||
|
shouldLiveInRoom: boolean;
|
||||||
|
shouldLiveInThread: boolean;
|
||||||
|
threadId?: string;
|
||||||
|
} {
|
||||||
|
// A thread relation is always only shown in a thread
|
||||||
|
if (event.isThreadRelation) {
|
||||||
|
return {
|
||||||
|
shouldLiveInRoom: false,
|
||||||
|
shouldLiveInThread: true,
|
||||||
|
threadId: event.relationEventId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentEventId = event.getAssociatedId();
|
||||||
|
const parentEvent = room?.findEventById(parentEventId) || events.find((mxEv: MatrixEvent) => (
|
||||||
|
mxEv.getId() === parentEventId
|
||||||
|
));
|
||||||
|
|
||||||
|
// A reaction targetting the thread root needs to be routed to both the
|
||||||
|
// the main timeline and the associated thread
|
||||||
|
const targetingThreadRoot = parentEvent?.isThreadRoot || roots.has(event.relationEventId);
|
||||||
|
if (targetingThreadRoot) {
|
||||||
|
return {
|
||||||
|
shouldLiveInRoom: true,
|
||||||
|
shouldLiveInThread: true,
|
||||||
|
threadId: event.relationEventId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the parent event also has an associated ID we want to re-run the
|
||||||
|
// computation for that parent event.
|
||||||
|
// In the case of the redaction of a reaction that targets a root event
|
||||||
|
// we want that redaction to be pushed to both timeline
|
||||||
|
if (parentEvent?.getAssociatedId()) {
|
||||||
|
return this.eventShouldLiveIn(parentEvent, room, events, roots);
|
||||||
|
} else {
|
||||||
|
// We've exhausted all scenarios, can safely assume that this event
|
||||||
|
// should live in the room timeline
|
||||||
|
return {
|
||||||
|
shouldLiveInRoom: true,
|
||||||
|
shouldLiveInThread: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public partitionThreadedEvents(events: MatrixEvent[]): [MatrixEvent[], MatrixEvent[]] {
|
public partitionThreadedEvents(events: MatrixEvent[]): [MatrixEvent[], MatrixEvent[]] {
|
||||||
// Indices to the events array, for readibility
|
// Indices to the events array, for readibility
|
||||||
const ROOM = 0;
|
const ROOM = 0;
|
||||||
@@ -9097,35 +9147,22 @@ export class MatrixClient extends EventEmitter {
|
|||||||
const threadRoots = this.findThreadRoots(events);
|
const threadRoots = this.findThreadRoots(events);
|
||||||
return events.reduce((memo, event: MatrixEvent) => {
|
return events.reduce((memo, event: MatrixEvent) => {
|
||||||
const room = this.getRoom(event.getRoomId());
|
const room = this.getRoom(event.getRoomId());
|
||||||
// An event should live in the thread timeline if
|
|
||||||
// - It's a reply in thread event
|
|
||||||
// - It's related to a reply in thread event
|
|
||||||
let shouldLiveInThreadTimeline = event.isThreadRelation;
|
|
||||||
if (!shouldLiveInThreadTimeline) {
|
|
||||||
const parentEventId = event.parentEventId;
|
|
||||||
const parentEvent = room?.findEventById(parentEventId) || events.find((mxEv: MatrixEvent) => {
|
|
||||||
return mxEv.getId() === parentEventId;
|
|
||||||
});
|
|
||||||
const targetingThreadRoot = parentEvent?.isThreadRoot || threadRoots.has(event.relationEventId);
|
|
||||||
|
|
||||||
if (targetingThreadRoot && !event.isThreadRelation && event.relationEventId) {
|
const {
|
||||||
// If we refer to the thread root, we should be copied
|
shouldLiveInRoom,
|
||||||
// into the thread as well as the main timeline.
|
shouldLiveInThread,
|
||||||
// This happens for reactions, annotations, poll votes etc.
|
threadId,
|
||||||
const copiedEvent = event.toSnapshot();
|
} = this.eventShouldLiveIn(event, room, events, threadRoots);
|
||||||
|
|
||||||
// The copied event is in this thread:
|
if (shouldLiveInRoom) {
|
||||||
copiedEvent.setThreadId(parentEventId);
|
memo[ROOM].push(event);
|
||||||
memo[THREAD].push(copiedEvent);
|
|
||||||
} else if (parentEvent?.isThreadRelation) {
|
|
||||||
// If our parent is in a thread, we are in that
|
|
||||||
// same thread too. (E.g. if I reply within a thread.)
|
|
||||||
shouldLiveInThreadTimeline = true;
|
|
||||||
event.setThreadId(parentEvent.threadRootId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldLiveInThread) {
|
||||||
|
event.setThreadId(threadId);
|
||||||
|
memo[THREAD].push(event);
|
||||||
}
|
}
|
||||||
const targetTimeline = shouldLiveInThreadTimeline ? THREAD : ROOM;
|
|
||||||
memo[targetTimeline].push(event);
|
|
||||||
return memo;
|
return memo;
|
||||||
}, [[], []]);
|
}, [[], []]);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import { Room } from "./room";
|
|||||||
import { Filter } from "../filter";
|
import { Filter } from "../filter";
|
||||||
import { EventType, RelationType } from "../@types/event";
|
import { EventType, RelationType } from "../@types/event";
|
||||||
import { RoomState } from "./room-state";
|
import { RoomState } from "./room-state";
|
||||||
import { Thread } from "./thread";
|
|
||||||
|
|
||||||
// var DEBUG = false;
|
// var DEBUG = false;
|
||||||
const DEBUG = true;
|
const DEBUG = true;
|
||||||
@@ -159,17 +158,12 @@ export class EventTimelineSet extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
|
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
|
||||||
*/
|
*/
|
||||||
public getPendingEvents(thread?: Thread): MatrixEvent[] {
|
public getPendingEvents(): MatrixEvent[] {
|
||||||
if (!this.room || !this.displayPendingEvents) {
|
if (!this.room || !this.displayPendingEvents) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const pendingEvents = this.room.getPendingEvents(thread);
|
return this.room.getPendingEvents();
|
||||||
if (this.filter) {
|
|
||||||
return this.filter.filterRoomTimeline(pendingEvents);
|
|
||||||
} else {
|
|
||||||
return pendingEvents;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the live timeline for this room.
|
* Get the live timeline for this room.
|
||||||
@@ -756,7 +750,7 @@ export class EventTimelineSet extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
public getRelationsForEvent(
|
public getRelationsForEvent(
|
||||||
eventId: string,
|
eventId: string,
|
||||||
relationType: RelationType,
|
relationType: RelationType | string,
|
||||||
eventType: EventType | string,
|
eventType: EventType | string,
|
||||||
): Relations | undefined {
|
): Relations | undefined {
|
||||||
if (!this.unstableClientRelationAggregation) {
|
if (!this.unstableClientRelationAggregation) {
|
||||||
@@ -774,6 +768,17 @@ export class EventTimelineSet extends EventEmitter {
|
|||||||
return relationsWithRelType[eventType];
|
return relationsWithRelType[eventType];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAllRelationsEventForEvent(eventId: string): MatrixEvent[] {
|
||||||
|
const relationsForEvent = this.relations[eventId] || {};
|
||||||
|
const events = [];
|
||||||
|
for (const relationsRecord of Object.values(relationsForEvent)) {
|
||||||
|
for (const relations of Object.values(relationsRecord)) {
|
||||||
|
events.push(...relations.getRelations());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an event as the target event if any Relations exist for it already
|
* Set an event as the target event if any Relations exist for it already
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -512,8 +512,7 @@ export class MatrixEvent extends EventEmitter {
|
|||||||
if (relatesTo?.rel_type === RelationType.Thread) {
|
if (relatesTo?.rel_type === RelationType.Thread) {
|
||||||
return relatesTo.event_id;
|
return relatesTo.event_id;
|
||||||
} else {
|
} else {
|
||||||
return this.threadId
|
return this.getThread()?.id || this.threadId;
|
||||||
|| this.getThread()?.id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,10 +536,6 @@ export class MatrixEvent extends EventEmitter {
|
|||||||
return !!threadDetails || (this.getThread()?.id === this.getId());
|
return !!threadDetails || (this.getThread()?.id === this.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public get parentEventId(): string {
|
|
||||||
return this.replyEventId || this.relationEventId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get replyEventId(): string {
|
public get replyEventId(): string {
|
||||||
// We're prefer ev.getContent() over ev.getWireContent() to make sure
|
// We're prefer ev.getContent() over ev.getWireContent() to make sure
|
||||||
// we grab the latest edit with potentially new relations. But we also
|
// we grab the latest edit with potentially new relations. But we also
|
||||||
@@ -1427,7 +1422,9 @@ export class MatrixEvent extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
public getAssociatedId(): string | undefined {
|
public getAssociatedId(): string | undefined {
|
||||||
const relation = this.getRelation();
|
const relation = this.getRelation();
|
||||||
if (relation) {
|
if (this.replyEventId) {
|
||||||
|
return this.replyEventId;
|
||||||
|
} else if (relation) {
|
||||||
return relation.event_id;
|
return relation.event_id;
|
||||||
} else if (this.isRedaction()) {
|
} else if (this.isRedaction()) {
|
||||||
return this.event.redacts;
|
return this.event.redacts;
|
||||||
@@ -1561,6 +1558,7 @@ export class MatrixEvent extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
public setThread(thread: Thread): void {
|
public setThread(thread: Thread): void {
|
||||||
this.thread = thread;
|
this.thread = thread;
|
||||||
|
this.setThreadId(thread.id);
|
||||||
this.reEmitter.reEmit(thread, [ThreadEvent.Ready, ThreadEvent.Update]);
|
this.reEmitter.reEmit(thread, [ThreadEvent.Ready, ThreadEvent.Update]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -171,11 +171,11 @@ export class Relations extends EventEmitter {
|
|||||||
* @return {Array}
|
* @return {Array}
|
||||||
* Relation events in insertion order.
|
* Relation events in insertion order.
|
||||||
*/
|
*/
|
||||||
public getRelations() {
|
public getRelations(): MatrixEvent[] {
|
||||||
return [...this.relations];
|
return [...this.relations];
|
||||||
}
|
}
|
||||||
|
|
||||||
private addAnnotationToAggregation(event: MatrixEvent) {
|
private addAnnotationToAggregation(event: MatrixEvent): void {
|
||||||
const { key } = event.getRelation();
|
const { key } = event.getRelation();
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return;
|
return;
|
||||||
@@ -204,7 +204,7 @@ export class Relations extends EventEmitter {
|
|||||||
eventsFromSender.add(event);
|
eventsFromSender.add(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeAnnotationFromAggregation(event: MatrixEvent) {
|
private removeAnnotationFromAggregation(event: MatrixEvent): void {
|
||||||
const { key } = event.getRelation();
|
const { key } = event.getRelation();
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return;
|
return;
|
||||||
@@ -240,7 +240,7 @@ export class Relations extends EventEmitter {
|
|||||||
* @param {MatrixEvent} redactedEvent
|
* @param {MatrixEvent} redactedEvent
|
||||||
* The original relation event that is about to be redacted.
|
* The original relation event that is about to be redacted.
|
||||||
*/
|
*/
|
||||||
private onBeforeRedaction = async (redactedEvent: MatrixEvent) => {
|
private onBeforeRedaction = async (redactedEvent: MatrixEvent): Promise<void> => {
|
||||||
if (!this.relations.has(redactedEvent)) {
|
if (!this.relations.has(redactedEvent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -512,16 +512,14 @@ export class Room extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
|
* @throws If <code>opts.pendingEventOrdering</code> was not 'detached'
|
||||||
*/
|
*/
|
||||||
public getPendingEvents(thread?: Thread): MatrixEvent[] {
|
public getPendingEvents(): MatrixEvent[] {
|
||||||
if (this.opts.pendingEventOrdering !== PendingEventOrdering.Detached) {
|
if (this.opts.pendingEventOrdering !== PendingEventOrdering.Detached) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Cannot call getPendingEvents with pendingEventOrdering == " +
|
"Cannot call getPendingEvents with pendingEventOrdering == " +
|
||||||
this.opts.pendingEventOrdering);
|
this.opts.pendingEventOrdering);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.pendingEventList.filter(event => {
|
return this.pendingEventList;
|
||||||
return !thread || thread.id === event.threadRootId;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1358,7 +1356,7 @@ export class Room extends EventEmitter {
|
|||||||
} else if (event.isThreadRoot) {
|
} else if (event.isThreadRoot) {
|
||||||
return this.threads.get(event.getId());
|
return this.threads.get(event.getId());
|
||||||
} else {
|
} else {
|
||||||
const parentEvent = this.findEventById(event.parentEventId);
|
const parentEvent = this.findEventById(event.getAssociatedId());
|
||||||
return this.findThreadForEvent(parentEvent);
|
return this.findThreadForEvent(parentEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1396,21 +1394,15 @@ export class Room extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit(ThreadEvent.Update, thread);
|
this.emit(ThreadEvent.Update, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createThread(rootEvent: MatrixEvent, events?: MatrixEvent[]): Thread | undefined {
|
public createThread(rootEvent: MatrixEvent, events: MatrixEvent[] = []): Thread | undefined {
|
||||||
|
const tl = this.getTimelineForEvent(rootEvent.getId());
|
||||||
|
const relatedEvents = tl?.getTimelineSet().getAllRelationsEventForEvent(rootEvent.getId()) ?? [];
|
||||||
|
|
||||||
const thread = new Thread(rootEvent, {
|
const thread = new Thread(rootEvent, {
|
||||||
initialEvents: events,
|
initialEvents: events.concat(relatedEvents),
|
||||||
room: this,
|
room: this,
|
||||||
client: this.client,
|
client: this.client,
|
||||||
});
|
});
|
||||||
@@ -1564,8 +1556,7 @@ export class Room extends EventEmitter {
|
|||||||
EventTimeline.setEventMetadata(event, this.getLiveTimeline().getState(EventTimeline.FORWARDS), false);
|
EventTimeline.setEventMetadata(event, this.getLiveTimeline().getState(EventTimeline.FORWARDS), false);
|
||||||
|
|
||||||
this.txnToEvent[txnId] = event;
|
this.txnToEvent[txnId] = event;
|
||||||
const thread = this.findThreadForEvent(event);
|
if (this.opts.pendingEventOrdering === PendingEventOrdering.Detached) {
|
||||||
if (this.opts.pendingEventOrdering === PendingEventOrdering.Detached && !thread) {
|
|
||||||
if (this.pendingEventList.some((e) => e.status === EventStatus.NOT_SENT)) {
|
if (this.pendingEventList.some((e) => e.status === EventStatus.NOT_SENT)) {
|
||||||
logger.warn("Setting event as NOT_SENT due to messages in the same state");
|
logger.warn("Setting event as NOT_SENT due to messages in the same state");
|
||||||
event.setStatus(EventStatus.NOT_SENT);
|
event.setStatus(EventStatus.NOT_SENT);
|
||||||
@@ -1581,8 +1572,7 @@ export class Room extends EventEmitter {
|
|||||||
|
|
||||||
if (event.isRedaction()) {
|
if (event.isRedaction()) {
|
||||||
const redactId = event.event.redacts;
|
const redactId = event.event.redacts;
|
||||||
let redactedEvent = this.pendingEventList &&
|
let redactedEvent = this.pendingEventList?.find(e => e.getId() === redactId);
|
||||||
this.pendingEventList.find(e => e.getId() === redactId);
|
|
||||||
if (!redactedEvent) {
|
if (!redactedEvent) {
|
||||||
redactedEvent = this.findEventById(redactId);
|
redactedEvent = this.findEventById(redactId);
|
||||||
}
|
}
|
||||||
@@ -1591,9 +1581,6 @@ export class Room extends EventEmitter {
|
|||||||
this.emit("Room.redaction", event, this);
|
this.emit("Room.redaction", event, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (thread) {
|
|
||||||
thread.addEvent(event, false);
|
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < this.timelineSets.length; i++) {
|
for (let i = 0; i < this.timelineSets.length; i++) {
|
||||||
const timelineSet = this.timelineSets[i];
|
const timelineSet = this.timelineSets[i];
|
||||||
@@ -1608,7 +1595,6 @@ export class Room extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.emit("Room.localEchoUpdated", event, this, null, null);
|
this.emit("Room.localEchoUpdated", event, this, null, null);
|
||||||
}
|
}
|
||||||
@@ -1666,7 +1652,9 @@ export class Room extends EventEmitter {
|
|||||||
const thread = this.findThreadForEvent(event);
|
const thread = this.findThreadForEvent(event);
|
||||||
if (thread) {
|
if (thread) {
|
||||||
thread.timelineSet.aggregateRelations(event);
|
thread.timelineSet.aggregateRelations(event);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (thread?.id === event.getAssociatedId() || !thread) {
|
||||||
// TODO: We should consider whether this means it would be a better
|
// TODO: We should consider whether this means it would be a better
|
||||||
// design to lift the relations handling up to the room instead.
|
// design to lift the relations handling up to the room instead.
|
||||||
for (let i = 0; i < this.timelineSets.length; i++) {
|
for (let i = 0; i < this.timelineSets.length; i++) {
|
||||||
@@ -1682,6 +1670,10 @@ export class Room extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getEventForTxnId(txnId: string): MatrixEvent {
|
||||||
|
return this.txnToEvent[txnId];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deal with the echo of a message we sent.
|
* Deal with the echo of a message we sent.
|
||||||
*
|
*
|
||||||
@@ -1696,7 +1688,7 @@ export class Room extends EventEmitter {
|
|||||||
* @fires module:client~MatrixClient#event:"Room.localEchoUpdated"
|
* @fires module:client~MatrixClient#event:"Room.localEchoUpdated"
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private handleRemoteEcho(remoteEvent: MatrixEvent, localEvent: MatrixEvent): void {
|
public handleRemoteEcho(remoteEvent: MatrixEvent, localEvent: MatrixEvent): void {
|
||||||
const oldEventId = localEvent.getId();
|
const oldEventId = localEvent.getId();
|
||||||
const newEventId = remoteEvent.getId();
|
const newEventId = remoteEvent.getId();
|
||||||
const oldStatus = localEvent.status;
|
const oldStatus = localEvent.status;
|
||||||
@@ -1721,7 +1713,9 @@ export class Room extends EventEmitter {
|
|||||||
const thread = this.findThreadForEvent(remoteEvent);
|
const thread = this.findThreadForEvent(remoteEvent);
|
||||||
if (thread) {
|
if (thread) {
|
||||||
thread.timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
|
thread.timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (thread?.id === remoteEvent.getAssociatedId() || !thread) {
|
||||||
for (let i = 0; i < this.timelineSets.length; i++) {
|
for (let i = 0; i < this.timelineSets.length; i++) {
|
||||||
const timelineSet = this.timelineSets[i];
|
const timelineSet = this.timelineSets[i];
|
||||||
|
|
||||||
@@ -1791,7 +1785,8 @@ export class Room extends EventEmitter {
|
|||||||
const thread = this.findThreadForEvent(event);
|
const thread = this.findThreadForEvent(event);
|
||||||
if (thread) {
|
if (thread) {
|
||||||
thread.timelineSet.replaceEventId(oldEventId, newEventId);
|
thread.timelineSet.replaceEventId(oldEventId, newEventId);
|
||||||
} else {
|
}
|
||||||
|
if (thread?.id === event.getAssociatedId() || !thread) {
|
||||||
// if the event was already in the timeline (which will be the case if
|
// if the event was already in the timeline (which will be the case if
|
||||||
// opts.pendingEventOrdering==chronological), we need to update the
|
// opts.pendingEventOrdering==chronological), we need to update the
|
||||||
// timeline map.
|
// timeline map.
|
||||||
|
|||||||
@@ -113,6 +113,27 @@ export class Thread extends TypedEventEmitter<ThreadEvent> {
|
|||||||
return this.room.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
return this.room.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private addEventToTimeline(event: MatrixEvent, toStartOfTimeline: boolean): void {
|
||||||
|
if (event.getUnsigned().transaction_id) {
|
||||||
|
const existingEvent = this.room.getEventForTxnId(event.getUnsigned().transaction_id);
|
||||||
|
if (existingEvent) {
|
||||||
|
// remote echo of an event we sent earlier
|
||||||
|
this.room.handleRemoteEcho(event, existingEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.findEventById(event.getId())) {
|
||||||
|
this.timelineSet.addEventToTimeline(
|
||||||
|
event,
|
||||||
|
this.liveTimeline,
|
||||||
|
toStartOfTimeline,
|
||||||
|
false,
|
||||||
|
this.roomState,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an event to the thread and updates
|
* Add an event to the thread and updates
|
||||||
* the tail/root references if needed
|
* the tail/root references if needed
|
||||||
@@ -123,36 +144,20 @@ export class Thread extends TypedEventEmitter<ThreadEvent> {
|
|||||||
// Add all incoming events to the thread's timeline set when there's
|
// Add all incoming events to the thread's timeline set when there's
|
||||||
// no server support
|
// no server support
|
||||||
if (!this.hasServerSideSupport) {
|
if (!this.hasServerSideSupport) {
|
||||||
if (this.timelineSet.findEventById(event.getId())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// all the relevant membership info to hydrate events with a sender
|
// all the relevant membership info to hydrate events with a sender
|
||||||
// is held in the main room timeline
|
// is held in the main room timeline
|
||||||
// We want to fetch the room state from there and pass it down to this thread
|
// We want to fetch the room state from there and pass it down to this thread
|
||||||
// timeline set to let it reconcile an event with its relevant RoomMember
|
// timeline set to let it reconcile an event with its relevant RoomMember
|
||||||
|
|
||||||
event.setThread(this);
|
event.setThread(this);
|
||||||
this.timelineSet.addEventToTimeline(
|
this.addEventToTimeline(event, toStartOfTimeline);
|
||||||
event,
|
|
||||||
this.liveTimeline,
|
|
||||||
toStartOfTimeline,
|
|
||||||
false,
|
|
||||||
this.roomState,
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.client.decryptEventIfNeeded(event, {});
|
await this.client.decryptEventIfNeeded(event, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasServerSideSupport && this.initialEventsFetched) {
|
if (this.hasServerSideSupport && this.initialEventsFetched) {
|
||||||
if (event.localTimestamp > this.lastReply().localTimestamp && !this.findEventById(event.getId())) {
|
if (event.localTimestamp > this.lastReply().localTimestamp) {
|
||||||
this.timelineSet.addEventToTimeline(
|
this.addEventToTimeline(event, false);
|
||||||
event,
|
|
||||||
this.liveTimeline,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
this.roomState,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1727,7 +1727,7 @@ export class SyncApi {
|
|||||||
// extractRelatedEvents(event: MatrixEvent, events: MatrixEvent[], relatedEvents: MatrixEvent[] = []): MatrixEvent[] {
|
// extractRelatedEvents(event: MatrixEvent, events: MatrixEvent[], relatedEvents: MatrixEvent[] = []): MatrixEvent[] {
|
||||||
// relatedEvents.push(event);
|
// relatedEvents.push(event);
|
||||||
|
|
||||||
// const parentEventId = event.parentEventId;
|
// const parentEventId = event.getAssociatedId();
|
||||||
// const parentEventIndex = events.findIndex(event => event.getId() === parentEventId);
|
// const parentEventIndex = events.findIndex(event => event.getId() === parentEventId);
|
||||||
|
|
||||||
// if (parentEventIndex > -1) {
|
// if (parentEventIndex > -1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user