1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-25 05:23:13 +03:00

Add experimental indicators for all threading related features

This commit is contained in:
Germain Souquet
2021-08-19 11:10:20 +01:00
parent 0eb8cbee4d
commit b7a5f81f95
4 changed files with 80 additions and 14 deletions

View File

@@ -193,7 +193,9 @@ export class MatrixEvent extends EventEmitter {
*/ */
private txnId: string = null; private txnId: string = null;
/** A reference to the event ID making the root of the thread /**
* @experimental
* A reference to the thread this event belongs to
*/ */
private thread: Thread = null; private thread: Thread = null;
@@ -391,6 +393,7 @@ export class MatrixEvent extends EventEmitter {
} }
/** /**
* @experimental
* Get the event ID of the replied event * Get the event ID of the replied event
*/ */
public get replyEventId(): string { public get replyEventId(): string {
@@ -1289,11 +1292,17 @@ export class MatrixEvent extends EventEmitter {
return this.txnId; return this.txnId;
} }
/**
* @experimental
*/
public setThread(thread: Thread): void { public setThread(thread: Thread): void {
this.thread = thread; this.thread = thread;
this.reEmitter.reEmit(thread, ["Thread.ready", "Thread.update"]); this.reEmitter.reEmit(thread, ["Thread.ready", "Thread.update"]);
} }
/**
* @experimental
*/
public getThread(): Thread { public getThread(): Thread {
return this.thread; return this.thread;
} }

View File

@@ -146,6 +146,9 @@ export class Room extends EventEmitter {
public oldState: RoomState; public oldState: RoomState;
public currentState: RoomState; public currentState: RoomState;
/**
* @experimental
*/
public threads = new Set<Thread>(); public threads = new Set<Thread>();
/** /**
@@ -860,7 +863,7 @@ export class Room extends EventEmitter {
} }
/** /**
* Get an event which is stored in our unfiltered timeline set * Get an event which is stored in our unfiltered timeline set or in a thread
* *
* @param {string} eventId event ID to look for * @param {string} eventId event ID to look for
* @return {?module:models/event.MatrixEvent} the given event, or undefined if unknown * @return {?module:models/event.MatrixEvent} the given event, or undefined if unknown
@@ -1065,6 +1068,9 @@ export class Room extends EventEmitter {
); );
} }
/**
* @experimental
*/
public addThread(thread: Thread): Set<Thread> { public addThread(thread: Thread): Set<Thread> {
this.threads.add(thread); this.threads.add(thread);
if (!thread.ready) { if (!thread.ready) {
@@ -1075,16 +1081,28 @@ export class Room extends EventEmitter {
return this.threads; return this.threads;
} }
/**
* @experimental
*/
public getThread(eventId: string): Thread { public getThread(eventId: string): Thread {
return this.getThreads().find(thread => { return this.getThreads().find(thread => {
return thread.id === eventId; return thread.id === eventId;
}); });
} }
/**
* @experimental
*/
public getThreads(): Thread[] { public getThreads(): Thread[] {
return Array.from(this.threads.values()); return Array.from(this.threads.values());
} }
/**
* Two threads starting from a different child event can end up
* with the same event root. This method ensures that the duplicates
* are removed
* @experimental
*/
private dedupeThreads = (readyThread): void => { private dedupeThreads = (readyThread): void => {
const threads = Array.from(this.threads); const threads = Array.from(this.threads);
if (threads.includes(readyThread)) { if (threads.includes(readyThread)) {
@@ -1274,6 +1292,10 @@ export class Room extends EventEmitter {
} }
} }
/**
* Add an event to a thread's timeline. Will fire "Thread.update"
* @experimental
*/
public addThreadedEvent(event: MatrixEvent): void { public addThreadedEvent(event: MatrixEvent): void {
if (event.getUnsigned().transaction_id) { if (event.getUnsigned().transaction_id) {
const existingEvent = this.txnToEvent[event.getUnsigned().transaction_id]; const existingEvent = this.txnToEvent[event.getUnsigned().transaction_id];

View File

@@ -20,14 +20,20 @@ import { MatrixEvent } from "./event";
import { EventTimelineSet } from './event-timeline-set'; import { EventTimelineSet } from './event-timeline-set';
import { Room } from './room'; import { Room } from './room';
/**
* @experimental
*/
export class Thread extends EventEmitter { export class Thread extends EventEmitter {
/**
* A reference to the event ID at the top of the thread
*/
private root: string; private root: string;
/**
* A reference to all the events ID at the bottom of the threads
*/
public tail = new Set<string>(); public tail = new Set<string>();
private events = new Map<string, MatrixEvent>();
private _timelineSet: EventTimelineSet; private _timelineSet: EventTimelineSet;
private decrypted = false;
constructor( constructor(
events: MatrixEvent[] = [], events: MatrixEvent[] = [],
public readonly room: Room, public readonly room: Room,
@@ -44,10 +50,11 @@ export class Thread extends EventEmitter {
/** /**
* 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
* Will fire "Thread.update"
* @param event The event to add * @param event The event to add
*/ */
public async addEvent(event: MatrixEvent): Promise<void> { public async addEvent(event: MatrixEvent): Promise<void> {
if (this.events.has(event.getId()) || event.status !== null) { if (this._timelineSet.findEventById(event.getId()) || event.status !== null) {
return; return;
} }
@@ -56,12 +63,11 @@ export class Thread extends EventEmitter {
} }
this.tail.add(event.getId()); this.tail.add(event.getId());
if (!event.replyEventId || !this.events.has(event.replyEventId)) { if (!event.replyEventId || !this._timelineSet.findEventById(event.replyEventId)) {
this.root = event.getId(); this.root = event.getId();
} }
event.setThread(this); event.setThread(this);
this.events.set(event.getId(), event);
this._timelineSet.addLiveEvent(event); this._timelineSet.addLiveEvent(event);
if (this.ready) { if (this.ready) {
@@ -72,6 +78,11 @@ export class Thread extends EventEmitter {
} }
} }
/**
* Completes the reply chain with all events
* missing from the current sync data
* Will fire "Thread.ready"
*/
public async fetchReplyChain(): Promise<void> { public async fetchReplyChain(): Promise<void> {
if (!this.ready) { if (!this.ready) {
let mxEvent = this.room.findEventById(this.rootEvent.replyEventId); let mxEvent = this.room.findEventById(this.rootEvent.replyEventId);
@@ -94,14 +105,15 @@ export class Thread extends EventEmitter {
private async decryptEvents(): Promise<void> { private async decryptEvents(): Promise<void> {
await Promise.allSettled( await Promise.allSettled(
Array.from(this.events.values()).map(event => { Array.from(this._timelineSet.getLiveTimeline().getEvents()).map(event => {
return this.client.decryptEventIfNeeded(event, {}); return this.client.decryptEventIfNeeded(event, {});
}), }),
); );
this.decrypted = true;
} }
/**
* Fetches an event over the network
*/
private async fetchEventById(roomId: string, eventId: string): Promise<MatrixEvent> { private async fetchEventById(roomId: string, eventId: string): Promise<MatrixEvent> {
const response = await this.client.http.authedRequest( const response = await this.client.http.authedRequest(
undefined, undefined,
@@ -111,10 +123,16 @@ export class Thread extends EventEmitter {
return new MatrixEvent(response); return new MatrixEvent(response);
} }
/**
* Finds an event by ID in the current thread
*/
public findEventById(eventId: string) { public findEventById(eventId: string) {
return this.events.get(eventId); return this._timelineSet.findEventById(eventId);
} }
/**
* Determines thread's ready status
*/
public get ready(): boolean { public get ready(): boolean {
return this.rootEvent.replyEventId === undefined; return this.rootEvent.replyEventId === undefined;
} }
@@ -126,8 +144,11 @@ export class Thread extends EventEmitter {
return this.root; return this.root;
} }
/**
* The thread root event
*/
public get rootEvent(): MatrixEvent { public get rootEvent(): MatrixEvent {
return this.events.get(this.root); return this.findEventById(this.root);
} }
/** /**
@@ -142,16 +163,22 @@ export class Thread extends EventEmitter {
*/ */
public get participants(): Set<string> { public get participants(): Set<string> {
const participants = new Set<string>(); const participants = new Set<string>();
this.events.forEach(event => { this._timelineSet.getLiveTimeline().getEvents().forEach(event => {
participants.add(event.getSender()); participants.add(event.getSender());
}); });
return participants; return participants;
} }
/**
* A read-only getter to access the timeline set
*/
public get timelineSet(): EventTimelineSet { public get timelineSet(): EventTimelineSet {
return this._timelineSet; return this._timelineSet;
} }
/**
* A getter for the last event added to the thread
*/
public get replyToEvent(): MatrixEvent { public get replyToEvent(): MatrixEvent {
const events = this._timelineSet.getLiveTimeline().getEvents(); const events = this._timelineSet.getLiveTimeline().getEvents();
return events[events.length -1]; return events[events.length -1];

View File

@@ -307,6 +307,11 @@ export class SyncApi {
}); });
} }
/**
* Split events between the ones that will end up in the main
* room timeline versus the one that need to be processed in a thread
* @experimental
*/
public partitionThreadedEvents(events: MatrixEvent[]): [MatrixEvent[], MatrixEvent[]] { public partitionThreadedEvents(events: MatrixEvent[]): [MatrixEvent[], MatrixEvent[]] {
return events.reduce((memo, event: MatrixEvent) => { return events.reduce((memo, event: MatrixEvent) => {
memo[event.replyEventId ? 1 : 0].push(event); memo[event.replyEventId ? 1 : 0].push(event);
@@ -1700,6 +1705,9 @@ export class SyncApi {
room.addLiveEvents(timelineEventList || [], null, fromCache); room.addLiveEvents(timelineEventList || [], null, fromCache);
} }
/**
* @experimental
*/
private processThreadEvents(room: Room, threadedEvents: MatrixEvent[]): void { private processThreadEvents(room: Room, threadedEvents: MatrixEvent[]): void {
threadedEvents.forEach(event => { threadedEvents.forEach(event => {
room.addThreadedEvent(event); room.addThreadedEvent(event);