Add support for MSC2762's timeline functionality

See https://github.com/matrix-org/matrix-widget-api/pull/41
This commit is contained in:
Travis Ralston 2021-08-25 18:16:40 -06:00
parent ee95e36a7c
commit 289ac34764
5 changed files with 119 additions and 48 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright 2020 - 2021 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.
@ -23,6 +23,7 @@ import {
MatrixCapabilities,
OpenIDRequestState,
SimpleObservable,
Symbols,
Widget,
WidgetDriver,
WidgetEventCapability,
@ -44,7 +45,8 @@ import { CHAT_EFFECTS } from "../../effects";
import { containsEmoji } from "../../effects/utils";
import dis from "../../dispatcher/dispatcher";
import { tryTransformPermalinkToLocalHref } from "../../utils/permalinks/Permalinks";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { IEvent, MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk";
// TODO: Purge this from the universe
@ -119,9 +121,9 @@ export class StopGapWidgetDriver extends WidgetDriver {
return new Set(iterableUnion(allowedSoFar, requested));
}
public async sendEvent(eventType: string, content: any, stateKey: string = null): Promise<ISendEventDetails> {
public async sendEvent(eventType: string, content: any, stateKey: string = null, targetRoomId: string = null): Promise<ISendEventDetails> {
const client = MatrixClientPeg.get();
const roomId = ActiveRoomObserver.activeRoomId;
const roomId = targetRoomId || ActiveRoomObserver.activeRoomId;
if (!client || !roomId) throw new Error("Not in a room or not attached to a client");
@ -145,48 +147,68 @@ export class StopGapWidgetDriver extends WidgetDriver {
return { roomId, eventId: r.event_id };
}
public async readRoomEvents(eventType: string, msgtype: string | undefined, limit: number): Promise<object[]> {
limit = limit > 0 ? Math.min(limit, 25) : 25; // arbitrary choice
private pickRooms(roomIds: (string | Symbols.AnyRoom)[] = null): Room[] {
const client = MatrixClientPeg.get();
const roomId = ActiveRoomObserver.activeRoomId;
const room = client.getRoom(roomId);
if (!client || !roomId || !room) throw new Error("Not in a room or not attached to a client");
if (!client) throw new Error("Not attached to a client");
const results: MatrixEvent[] = [];
const events = room.getLiveTimeline().getEvents(); // timelines are most recent last
for (let i = events.length - 1; i > 0; i--) {
if (results.length >= limit) break;
const ev = events[i];
if (ev.getType() !== eventType || ev.isState()) continue;
if (eventType === EventType.RoomMessage && msgtype && msgtype !== ev.getContent()['msgtype']) continue;
results.push(ev);
}
return results.map(e => e.getEffectiveEvent());
const targetRooms = roomIds
? (roomIds.includes(Symbols.AnyRoom) ? client.getVisibleRooms() : roomIds.map(r => client.getRoom(r)))
: [client.getRoom(ActiveRoomObserver.activeRoomId)];
return targetRooms.filter(r => !!r);
}
public async readStateEvents(eventType: string, stateKey: string | undefined, limit: number): Promise<object[]> {
limit = limit > 0 ? Math.min(limit, 100) : 100; // arbitrary choice
public async readRoomEvents(
eventType: string,
msgtype: string | undefined,
limitPerRoom: number,
roomIds: (string | Symbols.AnyRoom)[] = null,
): Promise<object[]> {
limitPerRoom = limitPerRoom > 0 ? Math.min(limitPerRoom, 25) : 25; // arbitrary choice
const client = MatrixClientPeg.get();
const roomId = ActiveRoomObserver.activeRoomId;
const room = client.getRoom(roomId);
if (!client || !roomId || !room) throw new Error("Not in a room or not attached to a client");
const rooms = this.pickRooms(roomIds);
const allResults: IEvent[] = [];
for (const room of rooms) {
const results: MatrixEvent[] = [];
const events = room.getLiveTimeline().getEvents(); // timelines are most recent last
for (let i = events.length - 1; i > 0; i--) {
if (results.length >= limitPerRoom) break;
const results: MatrixEvent[] = [];
const state: Map<string, MatrixEvent> = room.currentState.events.get(eventType);
if (state) {
if (stateKey === "" || !!stateKey) {
const forKey = state.get(stateKey);
if (forKey) results.push(forKey);
} else {
results.push(...Array.from(state.values()));
const ev = events[i];
if (ev.getType() !== eventType || ev.isState()) continue;
if (eventType === EventType.RoomMessage && msgtype && msgtype !== ev.getContent()['msgtype']) continue;
results.push(ev);
}
}
return results.slice(0, limit).map(e => e.event);
results.forEach(e => allResults.push(e.getEffectiveEvent()));
}
return allResults;
}
public async readStateEvents(
eventType: string,
stateKey: string | undefined,
limitPerRoom: number,
roomIds: (string | Symbols.AnyRoom)[] = null,
): Promise<object[]> {
limitPerRoom = limitPerRoom > 0 ? Math.min(limitPerRoom, 100) : 100; // arbitrary choice
const rooms = this.pickRooms(roomIds);
const allResults: IEvent[] = [];
for (const room of rooms) {
const results: MatrixEvent[] = [];
const state: Map<string, MatrixEvent> = room.currentState.events.get(eventType);
if (state) {
if (stateKey === "" || !!stateKey) {
const forKey = state.get(stateKey);
if (forKey) results.push(forKey);
} else {
results.push(...Array.from(state.values()));
}
}
results.slice(0, limitPerRoom).forEach(e => allResults.push(e.getEffectiveEvent()));
}
return allResults;
}
public async askOpenID(observer: SimpleObservable<IOpenIDUpdate>) {