Skip to content

Commit

Permalink
Update thread info after MSC3440 updates (#2209)
Browse files Browse the repository at this point in the history
  • Loading branch information
Germain authored Mar 2, 2022
1 parent 9b429c1 commit 4e4afdb
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { RelationType, UNSTABLE_FILTER_RELATION_SENDERS, UNSTABLE_FILTER_RELATION_TYPES } from "../../src";
import {
RelationType,
UNSTABLE_FILTER_RELATED_BY_REL_TYPES,
UNSTABLE_FILTER_RELATED_BY_SENDERS,
} from "../../src";
import { FilterComponent } from "../../src/filter-component";
import { mkEvent } from '../test-utils';

Expand Down Expand Up @@ -35,7 +39,7 @@ describe("Filter Component", function() {
it("should filter out events by relation participation", function() {
const currentUserId = '@me:server.org';
const filter = new FilterComponent({
[UNSTABLE_FILTER_RELATION_SENDERS.name]: currentUserId,
[UNSTABLE_FILTER_RELATED_BY_SENDERS.name]: [currentUserId],
}, currentUserId);

const threadRootNotParticipated = mkEvent({
Expand All @@ -60,7 +64,7 @@ describe("Filter Component", function() {
it("should keep events by relation participation", function() {
const currentUserId = '@me:server.org';
const filter = new FilterComponent({
[UNSTABLE_FILTER_RELATION_SENDERS.name]: currentUserId,
[UNSTABLE_FILTER_RELATED_BY_SENDERS.name]: [currentUserId],
}, currentUserId);

const threadRootParticipated = mkEvent({
Expand All @@ -84,7 +88,7 @@ describe("Filter Component", function() {

it("should filter out events by relation type", function() {
const filter = new FilterComponent({
[UNSTABLE_FILTER_RELATION_TYPES.name]: RelationType.Thread,
[UNSTABLE_FILTER_RELATED_BY_REL_TYPES.name]: [RelationType.Thread],
});

const referenceRelationEvent = mkEvent({
Expand All @@ -104,7 +108,7 @@ describe("Filter Component", function() {

it("should keep events by relation type", function() {
const filter = new FilterComponent({
[UNSTABLE_FILTER_RELATION_TYPES.name]: RelationType.Thread,
[UNSTABLE_FILTER_RELATED_BY_REL_TYPES.name]: [RelationType.Thread],
});

const threadRootEvent = mkEvent({
Expand Down
70 changes: 70 additions & 0 deletions spec/unit/room.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
/*
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
* This is an internal module. See {@link MatrixClient} for the public class.
* @module client
*/

import * as utils from "../test-utils";
import { DuplicateStrategy, EventStatus, MatrixEvent, PendingEventOrdering, RoomEvent } from "../../src";
import { EventTimeline } from "../../src/models/event-timeline";
import { Room } from "../../src/models/room";
import { RoomState } from "../../src/models/room-state";
import { RelationType, UNSTABLE_ELEMENT_FUNCTIONAL_USERS } from "../../src/@types/event";
import { TestClient } from "../TestClient";
import { Thread } from "../../src/models/thread";

describe("Room", function() {
const roomId = "!foo:bar";
Expand Down Expand Up @@ -1845,6 +1867,54 @@ describe("Room", function() {

expect(() => room.createThread(rootEvent, [])).not.toThrow();
});

it("should not add events before server supports is known", function() {
Thread.hasServerSideSupport = undefined;

const rootEvent = new MatrixEvent({
event_id: "$666",
room_id: roomId,
content: {},
unsigned: {
"age": 1,
"m.relations": {
[RelationType.Thread]: {
latest_event: null,
count: 1,
current_user_participated: false,
},
},
},
});

let age = 1;
function mkEvt(id): MatrixEvent {
return new MatrixEvent({
event_id: id,
room_id: roomId,
content: {
"m.relates_to": {
"rel_type": RelationType.Thread,
"event_id": "$666",
},
},
unsigned: {
"age": age++,
},
});
}

const thread = room.createThread(rootEvent, []);
expect(thread.length).toBe(0);

thread.addEvent(mkEvt("$1"));
expect(thread.length).toBe(0);

Thread.hasServerSideSupport = true;

thread.addEvent(mkEvt("$2"));
expect(thread.length).toBeGreaterThan(0);
});
});
});
});
16 changes: 10 additions & 6 deletions src/filter-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ limitations under the License.
*/

import { RelationType } from "./@types/event";
import { UNSTABLE_FILTER_RELATION_SENDERS, UNSTABLE_FILTER_RELATION_TYPES } from "./filter";
import {
UNSTABLE_FILTER_RELATED_BY_REL_TYPES,
UNSTABLE_FILTER_RELATED_BY_SENDERS,
} from "./filter";
import { MatrixEvent } from "./models/event";

/**
Expand Down Expand Up @@ -48,7 +51,8 @@ export interface IFilterComponent {
not_senders?: string[];
contains_url?: boolean;
limit?: number;
[UNSTABLE_FILTER_RELATION_TYPES.name]?: Array<RelationType | string>;
[UNSTABLE_FILTER_RELATED_BY_SENDERS.name]?: string[];
[UNSTABLE_FILTER_RELATED_BY_REL_TYPES.name]?: Array<RelationType | string>;
}
/* eslint-enable camelcase */

Expand Down Expand Up @@ -106,8 +110,8 @@ export class FilterComponent {
senders: this.filterJson.senders || null,
not_senders: this.filterJson.not_senders || [],
contains_url: this.filterJson.contains_url || null,
[UNSTABLE_FILTER_RELATION_SENDERS.name]: UNSTABLE_FILTER_RELATION_SENDERS.findIn(this.filterJson),
[UNSTABLE_FILTER_RELATION_TYPES.name]: UNSTABLE_FILTER_RELATION_TYPES.findIn(this.filterJson),
[UNSTABLE_FILTER_RELATED_BY_SENDERS.name]: UNSTABLE_FILTER_RELATED_BY_SENDERS.findIn(this.filterJson),
[UNSTABLE_FILTER_RELATED_BY_REL_TYPES.name]: UNSTABLE_FILTER_RELATED_BY_REL_TYPES.findIn(this.filterJson),
};
}

Expand Down Expand Up @@ -161,14 +165,14 @@ export class FilterComponent {
return false;
}

const relationTypesFilter = this.filterJson[UNSTABLE_FILTER_RELATION_TYPES.name];
const relationTypesFilter = this.filterJson[UNSTABLE_FILTER_RELATED_BY_REL_TYPES.name];
if (relationTypesFilter !== undefined) {
if (!this.arrayMatchesFilter(relationTypesFilter, relationTypes)) {
return false;
}
}

const relationSendersFilter = this.filterJson[UNSTABLE_FILTER_RELATION_SENDERS.name];
const relationSendersFilter = this.filterJson[UNSTABLE_FILTER_RELATED_BY_SENDERS.name];
if (relationSendersFilter !== undefined) {
if (!this.arrayMatchesFilter(relationSendersFilter, relationSenders)) {
return false;
Expand Down
12 changes: 6 additions & 6 deletions src/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ import { FilterComponent, IFilterComponent } from "./filter-component";
import { MatrixEvent } from "./models/event";
import { UnstableValue } from "./NamespacedValue";

export const UNSTABLE_FILTER_RELATION_SENDERS = new UnstableValue(
"relation_senders",
export const UNSTABLE_FILTER_RELATED_BY_SENDERS = new UnstableValue(
"related_by_senders",
"io.element.relation_senders",
);

export const UNSTABLE_FILTER_RELATION_TYPES = new UnstableValue(
"relation_types",
export const UNSTABLE_FILTER_RELATED_BY_REL_TYPES = new UnstableValue(
"related_by_rel_types",
"io.element.relation_types",
);

Expand Down Expand Up @@ -66,8 +66,8 @@ export interface IRoomEventFilter extends IFilterComponent {
lazy_load_members?: boolean;
include_redundant_members?: boolean;
types?: Array<EventType | string>;
[UNSTABLE_FILTER_RELATION_TYPES.name]?: Array<RelationType | string>;
[UNSTABLE_FILTER_RELATION_SENDERS.name]?: string[];
[UNSTABLE_FILTER_RELATED_BY_REL_TYPES.name]?: Array<RelationType | string>;
[UNSTABLE_FILTER_RELATED_BY_SENDERS.name]?: string[];
}

interface IStateFilter extends IRoomEventFilter {}
Expand Down
45 changes: 35 additions & 10 deletions src/models/thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ interface IThreadOpts {
* @experimental
*/
export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
public static hasServerSideSupport: boolean;
private static serverSupportPromise: Promise<boolean> | null;

/**
* A reference to all the events ID at the bottom of the threads
*/
Expand Down Expand Up @@ -91,6 +94,15 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
RoomEvent.TimelineReset,
]);

if (Thread.hasServerSideSupport === undefined) {
Thread.serverSupportPromise = this.client.doesServerSupportUnstableFeature("org.matrix.msc3440");
Thread.serverSupportPromise.then((serverSupportsThread) => {
Thread.hasServerSideSupport = serverSupportsThread;
}).catch(() => {
Thread.serverSupportPromise = null;
});
}

// If we weren't able to find the root event, it's probably missing
// and we define the thread ID from one of the thread relation
if (!rootEvent) {
Expand All @@ -107,11 +119,6 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
this.room.on(RoomEvent.Timeline, this.onEcho);
}

public get hasServerSideSupport(): boolean {
return this.client.cachedCapabilities
?.capabilities?.[RelationType.Thread]?.enabled;
}

private onEcho = (event: MatrixEvent) => {
if (this.timelineSet.eventIdToTimeline(event.getId())) {
this.emit(ThreadEvent.Update, this);
Expand Down Expand Up @@ -152,8 +159,12 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
* to the start (and not the end) of the timeline.
*/
public async addEvent(event: MatrixEvent, toStartOfTimeline = false): Promise<void> {
if (Thread.hasServerSideSupport === undefined) {
await Thread.serverSupportPromise;
}

// Add all incoming events to the thread's timeline set when there's no server support
if (!this.hasServerSideSupport) {
if (!Thread.hasServerSideSupport) {
// all the relevant membership info to hydrate events with a sender
// is held in the main room timeline
// We want to fetch the room state from there and pass it down to this thread
Expand All @@ -165,7 +176,7 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
await this.client.decryptEventIfNeeded(event, {});
}

if (this.hasServerSideSupport && this.initialEventsFetched) {
if (Thread.hasServerSideSupport && this.initialEventsFetched) {
if (event.localTimestamp > this.lastReply().localTimestamp) {
this.addEventToTimeline(event, false);
}
Expand All @@ -178,7 +189,7 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
const isThreadReply = event.getRelation()?.rel_type === RelationType.Thread;
// If no thread support exists we want to count all thread relation
// added as a reply. We can't rely on the bundled relationships count
if (!this.hasServerSideSupport && isThreadReply) {
if (!Thread.hasServerSideSupport && isThreadReply) {
this.replyCount++;
}

Expand All @@ -191,7 +202,7 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
// This counting only works when server side support is enabled
// as we started the counting from the value returned in the
// bundled relationship
if (this.hasServerSideSupport) {
if (Thread.hasServerSideSupport) {
this.replyCount++;
}

Expand All @@ -203,10 +214,17 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
}

private initialiseThread(rootEvent: MatrixEvent | undefined): void {
if (Thread.hasServerSideSupport === undefined) {
Thread.serverSupportPromise.then(() => {
this.initialiseThread(rootEvent);
});
return;
}

const bundledRelationship = rootEvent
?.getServerAggregatedRelation<IThreadBundledRelationship>(RelationType.Thread);

if (this.hasServerSideSupport && bundledRelationship) {
if (Thread.hasServerSideSupport && bundledRelationship) {
this.replyCount = bundledRelationship.count;
this._currentUserParticipated = bundledRelationship.current_user_participated;

Expand All @@ -221,6 +239,9 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
}

public async fetchInitialEvents(): Promise<boolean> {
if (Thread.hasServerSideSupport === undefined) {
await Thread.serverSupportPromise;
}
try {
await this.fetchEvents();
this.initialEventsFetched = true;
Expand Down Expand Up @@ -296,6 +317,10 @@ export class Thread extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
nextBatch?: string;
prevBatch?: string;
}> {
if (Thread.serverSupportPromise) {
await Thread.serverSupportPromise;
}

let {
originalEvent,
events,
Expand Down

0 comments on commit 4e4afdb

Please sign in to comment.