forked from mystiq/hydrogen-web
reference count archived rooms and keep track of active ones
so we don't create two instances for the same id, one for sync, and one for displaying, and hence updates from sync being pushed on a different instance than the one displaying, and not updating the view.
This commit is contained in:
parent
965700272b
commit
8b8214cd1b
4 changed files with 38 additions and 6 deletions
|
@ -81,6 +81,9 @@ export class RoomViewModel extends ViewModel {
|
|||
dispose() {
|
||||
super.dispose();
|
||||
this._room.off("change", this._onRoomChange);
|
||||
if (this._room.isArchived) {
|
||||
this._room.release();
|
||||
}
|
||||
if (this._clearUnreadTimout) {
|
||||
this._clearUnreadTimout.abort();
|
||||
this._clearUnreadTimout = null;
|
||||
|
|
|
@ -56,6 +56,7 @@ export class Session {
|
|||
this._sessionInfo = sessionInfo;
|
||||
this._rooms = new ObservableMap();
|
||||
this._roomUpdateCallback = (room, params) => this._rooms.update(room.id, params);
|
||||
this._activeArchivedRooms = new Map();
|
||||
this._invites = new ObservableMap();
|
||||
this._inviteUpdateCallback = (invite, params) => this._invites.update(invite.id, params);
|
||||
this._user = new User(sessionInfo.userId);
|
||||
|
@ -399,18 +400,21 @@ export class Session {
|
|||
}
|
||||
|
||||
/** @internal */
|
||||
createArchivedRoom(roomId) {
|
||||
return new ArchivedRoom({
|
||||
_createArchivedRoom(roomId) {
|
||||
const room = new ArchivedRoom({
|
||||
roomId,
|
||||
getSyncToken: this._getSyncToken,
|
||||
storage: this._storage,
|
||||
emitCollectionChange: () => {},
|
||||
releaseCallback: () => this._activeArchivedRooms.delete(roomId),
|
||||
hsApi: this._hsApi,
|
||||
mediaRepository: this._mediaRepository,
|
||||
user: this._user,
|
||||
createRoomEncryption: this._createRoomEncryption,
|
||||
platform: this._platform
|
||||
});
|
||||
this._activeArchivedRooms.set(roomId, room);
|
||||
return room;
|
||||
}
|
||||
|
||||
get invites() {
|
||||
|
@ -641,6 +645,8 @@ export class Session {
|
|||
return RoomStatus.joined;
|
||||
} else {
|
||||
const isInvited = !!this._invites.get(roomId);
|
||||
const txn = await this._storage.readTxn([this._storage.storeNames.archivedRoomSummary]);
|
||||
const isArchived = await txn.archivedRoomSummary.has(roomId);
|
||||
if (isInvited && isArchived) {
|
||||
return RoomStatus.invitedAndArchived;
|
||||
} else if (isInvited) {
|
||||
|
@ -668,13 +674,18 @@ export class Session {
|
|||
loadArchivedRoom(roomId, log = null) {
|
||||
return this._platform.logger.wrapOrRun(log, "loadArchivedRoom", async log => {
|
||||
log.set("id", roomId);
|
||||
const activeArchivedRoom = this._activeArchivedRooms.get(roomId);
|
||||
if (activeArchivedRoom) {
|
||||
activeArchivedRoom.retain();
|
||||
return activeArchivedRoom;
|
||||
}
|
||||
const txn = await this._storage.readTxn([
|
||||
this._storage.storeNames.archivedRoomSummary,
|
||||
this._storage.storeNames.roomMembers,
|
||||
]);
|
||||
const summary = await txn.archivedRoomSummary.get(roomId);
|
||||
if (summary) {
|
||||
const room = this.createArchivedRoom(roomId);
|
||||
const room = this._createArchivedRoom(roomId);
|
||||
await room.load(summary, txn, log);
|
||||
return room;
|
||||
}
|
||||
|
|
|
@ -309,7 +309,10 @@ export class Sync {
|
|||
_afterSync(sessionState, inviteStates, roomStates, archivedRoomStates, log) {
|
||||
log.wrap("session", log => this._session.afterSync(sessionState.changes, log), log.level.Detail);
|
||||
for(let ars of archivedRoomStates) {
|
||||
log.wrap("archivedRoom", log => ars.archivedRoom.afterSync(ars.changes, log), log.level.Detail);
|
||||
log.wrap("archivedRoom", log => {
|
||||
ars.archivedRoom.afterSync(ars.changes, log);
|
||||
ars.archivedRoom.release();
|
||||
}, log.level.Detail);
|
||||
}
|
||||
for(let rs of roomStates) {
|
||||
log.wrap("room", log => rs.room.afterSync(rs.changes, log), log.level.Detail);
|
||||
|
@ -407,12 +410,12 @@ export class Sync {
|
|||
// when adding a joined room during incremental sync,
|
||||
// always create the archived room to write the removal
|
||||
// of the archived summary
|
||||
archivedRoom = this._session.createArchivedRoom(roomId);
|
||||
archivedRoom = await this._session.loadArchivedRoom(roomId, log);
|
||||
} else if (membership === "leave") {
|
||||
if (roomState) {
|
||||
// we still have a roomState, so we just left it
|
||||
// in this case, create a new archivedRoom
|
||||
archivedRoom = this._session.createArchivedRoom(roomId);
|
||||
archivedRoom = await this._session.loadArchivedRoom(roomId, log);
|
||||
} else {
|
||||
// this is an update of an already left room, restore
|
||||
// it from storage first, so we can increment it.
|
||||
|
|
|
@ -21,6 +21,10 @@ import {RoomMember} from "./members/RoomMember.js";
|
|||
export class ArchivedRoom extends BaseRoom {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
// archived rooms are reference counted,
|
||||
// as they are not kept in memory when not needed
|
||||
this._releaseCallback = options.releaseCallback;
|
||||
this._retentionCount = 1;
|
||||
/**
|
||||
Some details from our own member event when being kicked or banned.
|
||||
We can't get this from the member store, because we don't store the reason field there.
|
||||
|
@ -29,6 +33,17 @@ export class ArchivedRoom extends BaseRoom {
|
|||
this._kickedBy = null;
|
||||
}
|
||||
|
||||
retain() {
|
||||
this._retentionCount += 1;
|
||||
}
|
||||
|
||||
release() {
|
||||
this._retentionCount -= 1;
|
||||
if (this._retentionCount === 0) {
|
||||
this._releaseCallback();
|
||||
}
|
||||
}
|
||||
|
||||
async _getKickAuthor(sender, txn) {
|
||||
const senderMember = await txn.roomMembers.get(this.id, sender);
|
||||
if (senderMember) {
|
||||
|
|
Loading…
Reference in a new issue