Modify the process for setting event metadata and refactor
parent
8786c97cdb
commit
56488d2c42
|
@ -84,8 +84,8 @@ export default class RoomHeader extends React.Component {
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
|
|
||||||
_exportConvertionalHistory = async () => {
|
_exportConversationalHistory = async () => {
|
||||||
await exportConversationalHistory(this.props.room, exportFormats.HTML, exportTypes.LAST_N_MESSAGES, 30);
|
await exportConversationalHistory(this.props.room, exportFormats.HTML, exportTypes.LAST_N_MESSAGES, 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -198,7 +198,7 @@ export default class RoomHeader extends React.Component {
|
||||||
|
|
||||||
const exportButton = <AccessibleTooltipButton
|
const exportButton = <AccessibleTooltipButton
|
||||||
className="mx_RoomHeader_button mx_ImageView_button_download"
|
className="mx_RoomHeader_button mx_ImageView_button_download"
|
||||||
onClick={this._exportConvertionalHistory}
|
onClick={this._exportConversationalHistory}
|
||||||
title={_t("Export conversation")} />;
|
title={_t("Export conversation")} />;
|
||||||
|
|
||||||
const rightRow =
|
const rightRow =
|
||||||
|
|
|
@ -4,10 +4,9 @@ import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||||
import { TimelineWindow } from "matrix-js-sdk/src/timeline-window";
|
import { TimelineWindow } from "matrix-js-sdk/src/timeline-window";
|
||||||
import { arrayFastClone } from "../arrays";
|
import { arrayFastClone } from "../arrays";
|
||||||
import { exportTypes } from "./exportUtils";
|
import { exportTypes } from "./exportUtils";
|
||||||
import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
|
|
||||||
|
|
||||||
export default abstract class Exporter {
|
export default abstract class Exporter {
|
||||||
constructor(protected room: Room, protected exportType: exportTypes, protected numberOfEvents?: number) {}
|
protected constructor(protected room: Room, protected exportType: exportTypes, protected numberOfEvents?: number) {}
|
||||||
|
|
||||||
protected getTimelineConversation = () : MatrixEvent[] => {
|
protected getTimelineConversation = () : MatrixEvent[] => {
|
||||||
if (!this.room) return;
|
if (!this.room) return;
|
||||||
|
@ -34,37 +33,32 @@ export default abstract class Exporter {
|
||||||
return events;
|
return events;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected eventToJson(ev) {
|
protected setEventMetadata = (event: MatrixEvent) => {
|
||||||
const jsonEvent = ev.toJSON();
|
const client = MatrixClientPeg.get();
|
||||||
const e = ev.isEncrypted() ? jsonEvent.decrypted : jsonEvent;
|
const roomState = client.getRoom(this.room.roomId).currentState;
|
||||||
if (ev.isEncrypted()) {
|
event.sender = roomState.getSentinelMember(
|
||||||
e.curve25519Key = ev.getSenderKey();
|
event.getSender(),
|
||||||
e.ed25519Key = ev.getClaimedEd25519Key();
|
);
|
||||||
e.algorithm = ev.getWireContent().algorithm;
|
if (event.getType() === "m.room.member") {
|
||||||
e.forwardingCurve25519KeyChain = ev.getForwardingCurve25519KeyChain();
|
event.target = roomState.getSentinelMember(
|
||||||
} else {
|
event.getStateKey(),
|
||||||
delete e.curve25519Key;
|
);
|
||||||
delete e.ed25519Key;
|
|
||||||
delete e.algorithm;
|
|
||||||
delete e.forwardingCurve25519KeyChain;
|
|
||||||
}
|
}
|
||||||
return e;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected getRequiredEvents = async () : Promise<MatrixEvent[]> => {
|
protected getRequiredEvents = async () : Promise<MatrixEvent[]> => {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const eventMapper = client.getEventMapper({ preventReEmit: true });
|
const eventMapper = client.getEventMapper();
|
||||||
|
|
||||||
let prevToken: string|null = null;
|
let prevToken: string|null = null;
|
||||||
let limit = this.numberOfEvents || Number.MAX_VALUE;
|
let limit = this.numberOfEvents || Number.MAX_VALUE;
|
||||||
let events: MatrixEvent[] = [];
|
let events: MatrixEvent[] = [];
|
||||||
const stateRes: any[] = [];
|
|
||||||
while (limit) {
|
while (limit) {
|
||||||
const eventsPerCrawl = Math.min(limit, 100);
|
const eventsPerCrawl = Math.min(limit, 100);
|
||||||
const res: any = await client.createMessagesRequest(this.room.roomId, prevToken, eventsPerCrawl, "b");
|
const res: any = await client.createMessagesRequest(this.room.roomId, prevToken, eventsPerCrawl, "b");
|
||||||
|
|
||||||
if (res.state) stateRes.push(...res.state);
|
|
||||||
if (res.chunk.length === 0) break;
|
if (res.chunk.length === 0) break;
|
||||||
|
|
||||||
limit -= eventsPerCrawl;
|
limit -= eventsPerCrawl;
|
||||||
|
@ -75,79 +69,25 @@ export default abstract class Exporter {
|
||||||
|
|
||||||
prevToken = res.end;
|
prevToken = res.end;
|
||||||
}
|
}
|
||||||
events = events.reverse()
|
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
|
const decryptionPromises = events
|
||||||
.filter(event => event.isEncrypted())
|
.filter(event => event.isEncrypted())
|
||||||
.map(event => {
|
.map(event => {
|
||||||
return client.decryptEventIfNeeded(event, {
|
return client.decryptEventIfNeeded(event, {
|
||||||
isRetry: true,
|
isRetry: true,
|
||||||
emit: false,
|
emit: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Let us wait for all the events to get decrypted.
|
//Wait for all the events to get decrypted.
|
||||||
await Promise.all(decryptionPromises);
|
await Promise.all(decryptionPromises);
|
||||||
|
|
||||||
const eventsWithProfile = events.map((ev) => {
|
events.map((event) => {
|
||||||
const e = this.eventToJson(ev);
|
return this.setEventMetadata(event);
|
||||||
|
})
|
||||||
|
|
||||||
let profile: any = {};
|
return events;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract export(): Promise<Blob>;
|
abstract export(): Promise<Blob>;
|
||||||
|
|
|
@ -172,8 +172,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
|
|
||||||
protected hasAvatar(event: MatrixEvent): boolean {
|
protected hasAvatar(event: MatrixEvent): boolean {
|
||||||
const member = event.sender;
|
const member = event.sender;
|
||||||
if (member.getMxcAvatarUrl()) return true;
|
return !!member.getMxcAvatarUrl();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async saveAvatarIfNeeded(event: MatrixEvent) {
|
protected async saveAvatarIfNeeded(event: MatrixEvent) {
|
||||||
|
@ -244,8 +243,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
}
|
}
|
||||||
const fileDate = formatFullDateNoDay(new Date(event.getTs()));
|
const fileDate = formatFullDateNoDay(new Date(event.getTs()));
|
||||||
const [fileName, fileExt] = this.splitFileName(event.getContent().body);
|
const [fileName, fileExt] = this.splitFileName(event.getContent().body);
|
||||||
const filePath = fileDirectory + "/" + fileName + '-' + fileDate + fileExt;
|
return fileDirectory + "/" + fileName + '-' + fileDate + fileExt;
|
||||||
return filePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,7 +311,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async export() {
|
public async export() {
|
||||||
const res = this.getTimelineConversation();
|
const res = await this.getRequiredEvents();
|
||||||
const html = await this.createHTML(res);
|
const html = await this.createHTML(res);
|
||||||
|
|
||||||
this.zip.file("index.html", html);
|
this.zip.file("index.html", html);
|
||||||
|
@ -342,7 +340,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
const blobPiece = blob.slice(fPointer, fPointer + sliceSize);
|
const blobPiece = blob.slice(fPointer, fPointer + sliceSize);
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
|
||||||
const waiter = new Promise<void>((resolve, reject) => {
|
const waiter = new Promise<void>((resolve) => {
|
||||||
reader.onloadend = evt => {
|
reader.onloadend = evt => {
|
||||||
const arrayBufferNew: any = evt.target.result;
|
const arrayBufferNew: any = evt.target.result;
|
||||||
const uint8ArrayNew = new Uint8Array(arrayBufferNew);
|
const uint8ArrayNew = new Uint8Array(arrayBufferNew);
|
||||||
|
@ -353,7 +351,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
});
|
});
|
||||||
await waiter;
|
await waiter;
|
||||||
}
|
}
|
||||||
writer.close();
|
await writer.close();
|
||||||
|
|
||||||
return blob;
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue