2021-05-24 15:18:13 +00:00
|
|
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
2021-05-24 15:50:16 +00:00
|
|
|
import { Room } from "matrix-js-sdk/src/models/room";
|
2021-06-03 07:51:56 +00:00
|
|
|
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
|
|
|
import { TimelineWindow } from "matrix-js-sdk/src/timeline-window";
|
|
|
|
import { arrayFastClone } from "../arrays";
|
2021-06-04 09:38:17 +00:00
|
|
|
import { exportTypes } from "./exportUtils";
|
|
|
|
import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
|
2021-05-24 15:18:13 +00:00
|
|
|
|
2021-06-03 08:09:14 +00:00
|
|
|
export default abstract class Exporter {
|
2021-06-04 09:38:17 +00:00
|
|
|
constructor(protected room: Room, protected exportType: exportTypes, protected numberOfEvents?: number) {}
|
2021-06-03 07:51:56 +00:00
|
|
|
|
2021-06-03 08:09:14 +00:00
|
|
|
protected getTimelineConversation = () : MatrixEvent[] => {
|
2021-06-03 07:51:56 +00:00
|
|
|
if (!this.room) return;
|
|
|
|
|
|
|
|
const cli = MatrixClientPeg.get();
|
|
|
|
|
|
|
|
const timelineSet = this.room.getUnfilteredTimelineSet();
|
|
|
|
|
|
|
|
const timelineWindow = new TimelineWindow(
|
|
|
|
cli, timelineSet,
|
|
|
|
{windowLimit: Number.MAX_VALUE});
|
|
|
|
|
|
|
|
timelineWindow.load(null, 30);
|
|
|
|
|
2021-06-04 09:38:17 +00:00
|
|
|
const events: MatrixEvent[] = timelineWindow.getEvents();
|
2021-06-03 07:51:56 +00:00
|
|
|
|
|
|
|
// Clone and reverse the events so that we preserve the order
|
|
|
|
arrayFastClone(events)
|
|
|
|
.reverse()
|
|
|
|
.forEach(event => {
|
|
|
|
cli.decryptEventIfNeeded(event);
|
|
|
|
});
|
|
|
|
|
|
|
|
return events;
|
|
|
|
};
|
|
|
|
|
2021-06-04 09:38:17 +00:00
|
|
|
protected eventToJson(ev) {
|
|
|
|
const jsonEvent = ev.toJSON();
|
|
|
|
const e = ev.isEncrypted() ? jsonEvent.decrypted : jsonEvent;
|
|
|
|
if (ev.isEncrypted()) {
|
|
|
|
e.curve25519Key = ev.getSenderKey();
|
|
|
|
e.ed25519Key = ev.getClaimedEd25519Key();
|
|
|
|
e.algorithm = ev.getWireContent().algorithm;
|
|
|
|
e.forwardingCurve25519KeyChain = ev.getForwardingCurve25519KeyChain();
|
|
|
|
} else {
|
|
|
|
delete e.curve25519Key;
|
|
|
|
delete e.ed25519Key;
|
|
|
|
delete e.algorithm;
|
|
|
|
delete e.forwardingCurve25519KeyChain;
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected getRequiredEvents = async () : Promise<MatrixEvent[]> => {
|
|
|
|
const client = MatrixClientPeg.get();
|
|
|
|
const eventMapper = client.getEventMapper({ preventReEmit: true });
|
|
|
|
|
|
|
|
let prevToken: string|null = null;
|
|
|
|
let limit = this.numberOfEvents || Number.MAX_VALUE;
|
|
|
|
let events: MatrixEvent[] = [];
|
|
|
|
const stateRes: any[] = [];
|
|
|
|
while (limit) {
|
|
|
|
const eventsPerCrawl = Math.min(limit, 100);
|
2021-06-05 05:57:08 +00:00
|
|
|
const res: any = await client.createMessagesRequest(this.room.roomId, prevToken, eventsPerCrawl, "b");
|
2021-06-04 09:38:17 +00:00
|
|
|
|
|
|
|
if (res.state) stateRes.push(...res.state);
|
|
|
|
if (res.chunk.length === 0) break;
|
|
|
|
|
|
|
|
limit -= eventsPerCrawl;
|
|
|
|
|
|
|
|
const matrixEvents: MatrixEvent[] = res.chunk.map(eventMapper);
|
|
|
|
|
|
|
|
matrixEvents.forEach(mxEv => events.push(mxEv));
|
|
|
|
|
|
|
|
prevToken = res.end;
|
|
|
|
}
|
|
|
|
events = events.reverse()
|
|
|
|
let stateEvents = [];
|
|
|
|
if (stateRes !== undefined) {
|
|
|
|
stateEvents = stateRes.map(eventMapper);
|
|
|
|
}
|
|
|
|
|
|
|
|
const profiles = {};
|
|
|
|
|
|
|
|
stateEvents.forEach(ev => {
|
|
|
|
if (ev.event.content &&
|
|
|
|
ev.event.content.membership === "join") {
|
|
|
|
profiles[ev.event.sender] = {
|
|
|
|
displayname: ev.event.content.displayname,
|
|
|
|
avatar_url: ev.event.content.avatar_url,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const decryptionPromises = events
|
|
|
|
.filter(event => event.isEncrypted())
|
|
|
|
.map(event => {
|
|
|
|
return client.decryptEventIfNeeded(event, {
|
|
|
|
isRetry: true,
|
|
|
|
emit: false,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Let us wait for all the events to get decrypted.
|
|
|
|
await Promise.all(decryptionPromises);
|
|
|
|
|
|
|
|
const eventsWithProfile = events.map((ev) => {
|
|
|
|
const e = this.eventToJson(ev);
|
|
|
|
|
|
|
|
let profile: any = {};
|
|
|
|
if (e.sender in profiles) profile = profiles[e.sender];
|
|
|
|
const object = {
|
|
|
|
event: e,
|
|
|
|
profile: profile,
|
|
|
|
};
|
|
|
|
return object;
|
|
|
|
});
|
|
|
|
|
|
|
|
const matrixEvents = eventsWithProfile.map(e => {
|
|
|
|
const matrixEvent = eventMapper(e.event);
|
|
|
|
|
|
|
|
const member = new RoomMember(this.room.roomId, matrixEvent.getSender());
|
|
|
|
|
|
|
|
member.name = e.profile.displayname;
|
|
|
|
|
|
|
|
const memberEvent = eventMapper(
|
|
|
|
{
|
|
|
|
content: {
|
|
|
|
membership: "join",
|
|
|
|
avatar_url: e.profile.avatar_url,
|
|
|
|
displayname: e.profile.displayname,
|
|
|
|
},
|
|
|
|
type: "m.room.member",
|
|
|
|
event_id: matrixEvent.getId() + ":eventIndex",
|
|
|
|
room_id: matrixEvent.getRoomId(),
|
|
|
|
sender: matrixEvent.getSender(),
|
|
|
|
origin_server_ts: matrixEvent.getTs(),
|
|
|
|
state_key: matrixEvent.getSender(),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
member.events.member = memberEvent;
|
|
|
|
matrixEvent.sender = member;
|
|
|
|
|
|
|
|
return matrixEvent;
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return matrixEvents;
|
|
|
|
}
|
|
|
|
|
2021-05-24 15:50:16 +00:00
|
|
|
abstract export(): Promise<Blob>;
|
2021-05-24 15:18:13 +00:00
|
|
|
}
|