This repository has been archived on 2022-08-19. You can view files and clone it, but cannot push or open issues or pull requests.
hydrogen-web/src/matrix/room/Room.js

135 lines
4.7 KiB
JavaScript
Raw Normal View History

2020-04-21 01:05:53 +05:30
import {EventEmitter} from "../../utils/EventEmitter.js";
import {RoomSummary} from "./RoomSummary.js";
import {SyncWriter} from "./timeline/persistence/SyncWriter.js";
import {GapWriter} from "./timeline/persistence/GapWriter.js";
import {Timeline} from "./timeline/Timeline.js";
import {FragmentIdComparer} from "./timeline/FragmentIdComparer.js";
import {SendQueue} from "./sending/SendQueue.js";
2018-12-21 19:05:24 +05:30
export class Room extends EventEmitter {
constructor({roomId, storage, hsApi, emitCollectionChange, sendScheduler, pendingEvents, user}) {
2019-02-21 04:18:16 +05:30
super();
this._roomId = roomId;
this._storage = storage;
this._hsApi = hsApi;
2019-02-11 01:55:29 +05:30
this._summary = new RoomSummary(roomId);
this._fragmentIdComparer = new FragmentIdComparer([]);
this._syncWriter = new SyncWriter({roomId, fragmentIdComparer: this._fragmentIdComparer});
2019-02-21 04:18:16 +05:30
this._emitCollectionChange = emitCollectionChange;
this._sendQueue = new SendQueue({roomId, storage, sendScheduler, pendingEvents});
this._timeline = null;
this._user = user;
2018-12-21 19:05:24 +05:30
}
async writeSync(roomResponse, membership, txn) {
const summaryChanges = this._summary.writeSync(roomResponse, membership, txn);
const {entries, newLiveKey} = await this._syncWriter.writeSync(roomResponse, txn);
let removedPendingEvents;
if (roomResponse.timeline && roomResponse.timeline.events) {
removedPendingEvents = this._sendQueue.removeRemoteEchos(roomResponse.timeline.events, txn);
}
return {summaryChanges, newTimelineEntries: entries, newLiveKey, removedPendingEvents};
}
afterSync({summaryChanges, newTimelineEntries, newLiveKey, removedPendingEvents}) {
2020-03-15 01:19:15 +05:30
this._syncWriter.afterSync(newLiveKey);
if (summaryChanges) {
this._summary.afterSync(summaryChanges);
2019-02-21 04:18:16 +05:30
this.emit("change");
this._emitCollectionChange(this);
2019-02-21 04:18:16 +05:30
}
if (this._timeline) {
this._timeline.appendLiveEntries(newTimelineEntries);
}
if (removedPendingEvents) {
this._sendQueue.emitRemovals(removedPendingEvents);
}
2018-12-21 19:05:24 +05:30
}
2019-07-27 02:10:39 +05:30
resumeSending() {
this._sendQueue.resumeSending();
}
2019-02-11 01:55:29 +05:30
load(summary, txn) {
this._summary.load(summary);
return this._syncWriter.load(txn);
2018-12-21 19:05:24 +05:30
}
2019-02-27 03:15:58 +05:30
sendEvent(eventType, content) {
return this._sendQueue.enqueueEvent(eventType, content);
}
2020-03-22 04:10:40 +05:30
/** @public */
async fillGap(fragmentEntry, amount) {
const response = await this._hsApi.messages(this._roomId, {
from: fragmentEntry.token,
dir: fragmentEntry.direction.asApiString(),
limit: amount,
filter: {lazy_load_members: true}
}).response();
const txn = await this._storage.readWriteTxn([
this._storage.storeNames.pendingEvents,
this._storage.storeNames.timelineEvents,
this._storage.storeNames.timelineFragments,
]);
let removedPendingEvents;
let gapResult;
try {
// detect remote echos of pending messages in the gap
removedPendingEvents = this._sendQueue.removeRemoteEchos(response.chunk, txn);
// write new events into gap
const gapWriter = new GapWriter({
roomId: this._roomId,
storage: this._storage,
fragmentIdComparer: this._fragmentIdComparer
});
gapResult = await gapWriter.writeFragmentFill(fragmentEntry, response, txn);
} catch (err) {
txn.abort();
throw err;
}
await txn.complete();
// once txn is committed, update in-memory state & emit events
for (const fragment of gapResult.fragments) {
this._fragmentIdComparer.add(fragment);
}
if (removedPendingEvents) {
this._sendQueue.emitRemovals(removedPendingEvents);
}
2020-03-22 04:10:40 +05:30
if (this._timeline) {
this._timeline.addGapEntries(gapResult.entries);
2020-03-22 04:10:40 +05:30
}
}
2019-02-27 03:15:58 +05:30
get name() {
return this._summary.name;
}
get id() {
return this._roomId;
}
async openTimeline() {
if (this._timeline) {
throw new Error("not dealing with load race here for now");
}
console.log(`opening the timeline for ${this._roomId}`);
this._timeline = new Timeline({
roomId: this.id,
storage: this._storage,
fragmentIdComparer: this._fragmentIdComparer,
pendingEvents: this._sendQueue.pendingEvents,
closeCallback: () => {
console.log(`closing the timeline for ${this._roomId}`);
this._timeline = null;
},
user: this._user,
});
await this._timeline.load();
return this._timeline;
}
2019-02-21 04:18:16 +05:30
}