mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 11:35:04 +01:00
pass memberchanges around instead of members
so we can easily tell how their membership changes, (e.g. join -> left) which we'll need for device tracking. Not adding this to RoomMember because RoomMember also needs to be able to represent a member loaded from storage which doesn't contain this error. A MemberChange exists only within a sync.
This commit is contained in:
parent
164384f312
commit
8482bc95ec
@ -51,7 +51,7 @@ export class Room extends EventEmitter {
|
|||||||
membership,
|
membership,
|
||||||
isInitialSync, isTimelineOpen,
|
isInitialSync, isTimelineOpen,
|
||||||
txn);
|
txn);
|
||||||
const {entries, newLiveKey, changedMembers} = await this._syncWriter.writeSync(roomResponse, txn);
|
const {entries, newLiveKey, memberChanges} = await this._syncWriter.writeSync(roomResponse, txn);
|
||||||
// fetch new members while we have txn open,
|
// fetch new members while we have txn open,
|
||||||
// but don't make any in-memory changes yet
|
// but don't make any in-memory changes yet
|
||||||
let heroChanges;
|
let heroChanges;
|
||||||
@ -60,7 +60,7 @@ export class Room extends EventEmitter {
|
|||||||
if (!this._heroes) {
|
if (!this._heroes) {
|
||||||
this._heroes = new Heroes(this._roomId);
|
this._heroes = new Heroes(this._roomId);
|
||||||
}
|
}
|
||||||
heroChanges = await this._heroes.calculateChanges(summaryChanges.heroes, changedMembers, txn);
|
heroChanges = await this._heroes.calculateChanges(summaryChanges.heroes, memberChanges, txn);
|
||||||
}
|
}
|
||||||
let removedPendingEvents;
|
let removedPendingEvents;
|
||||||
if (roomResponse.timeline && roomResponse.timeline.events) {
|
if (roomResponse.timeline && roomResponse.timeline.events) {
|
||||||
@ -71,22 +71,22 @@ export class Room extends EventEmitter {
|
|||||||
newTimelineEntries: entries,
|
newTimelineEntries: entries,
|
||||||
newLiveKey,
|
newLiveKey,
|
||||||
removedPendingEvents,
|
removedPendingEvents,
|
||||||
changedMembers,
|
memberChanges,
|
||||||
heroChanges
|
heroChanges
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @package */
|
/** @package */
|
||||||
afterSync({summaryChanges, newTimelineEntries, newLiveKey, removedPendingEvents, changedMembers, heroChanges}) {
|
afterSync({summaryChanges, newTimelineEntries, newLiveKey, removedPendingEvents, memberChanges, heroChanges}) {
|
||||||
this._syncWriter.afterSync(newLiveKey);
|
this._syncWriter.afterSync(newLiveKey);
|
||||||
if (changedMembers.length) {
|
if (memberChanges.size) {
|
||||||
if (this._changedMembersDuringSync) {
|
if (this._changedMembersDuringSync) {
|
||||||
for (const member of changedMembers) {
|
for (const [userId, memberChange] of memberChanges.entries()) {
|
||||||
this._changedMembersDuringSync.set(member.userId, member);
|
this._changedMembersDuringSync.set(userId, memberChange.member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this._memberList) {
|
if (this._memberList) {
|
||||||
this._memberList.afterSync(changedMembers);
|
this._memberList.afterSync(memberChanges);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let emitChange = false;
|
let emitChange = false;
|
||||||
|
@ -42,11 +42,11 @@ export class Heroes {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string[]} newHeroes array of user ids
|
* @param {string[]} newHeroes array of user ids
|
||||||
* @param {RoomMember[]} changedMembers array of changed members in this sync
|
* @param {Map<string, MemberChange>} memberChanges map of changed memberships
|
||||||
* @param {Transaction} txn
|
* @param {Transaction} txn
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
async calculateChanges(newHeroes, changedMembers, txn) {
|
async calculateChanges(newHeroes, memberChanges, txn) {
|
||||||
const updatedHeroMembers = new Map();
|
const updatedHeroMembers = new Map();
|
||||||
const removedUserIds = [];
|
const removedUserIds = [];
|
||||||
// remove non-present members
|
// remove non-present members
|
||||||
@ -56,9 +56,9 @@ export class Heroes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// update heroes with synced member changes
|
// update heroes with synced member changes
|
||||||
for (const member of changedMembers) {
|
for (const [userId, memberChange] of memberChanges.entries()) {
|
||||||
if (this._members.has(member.userId) || newHeroes.indexOf(member.userId) !== -1) {
|
if (this._members.has(userId) || newHeroes.indexOf(userId) !== -1) {
|
||||||
updatedHeroMembers.set(member.userId, member);
|
updatedHeroMembers.set(userId, memberChange.member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// load member for new heroes from storage
|
// load member for new heroes from storage
|
||||||
|
@ -26,9 +26,9 @@ export class MemberList {
|
|||||||
this._retentionCount = 1;
|
this._retentionCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
afterSync(updatedMembers) {
|
afterSync(memberChanges) {
|
||||||
for (const member of updatedMembers) {
|
for (const [userId, memberChange] of memberChanges.entries()) {
|
||||||
this._members.add(member.userId, member);
|
this._members.add(userId, memberChange.member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,3 +99,30 @@ export class RoomMember {
|
|||||||
return this._data;
|
return this._data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MemberChange {
|
||||||
|
constructor(roomId, memberEvent) {
|
||||||
|
this._roomId = roomId;
|
||||||
|
this._memberEvent = memberEvent;
|
||||||
|
this._member = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get member() {
|
||||||
|
if (!this._member) {
|
||||||
|
this._member = RoomMember.fromMemberEvent(this._roomId, this._memberEvent);
|
||||||
|
}
|
||||||
|
return this._member;
|
||||||
|
}
|
||||||
|
|
||||||
|
userId() {
|
||||||
|
return this._memberEvent.state_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
previousMembership() {
|
||||||
|
return this._memberEvent.unsigned?.prev_content?.membership;
|
||||||
|
}
|
||||||
|
|
||||||
|
membership() {
|
||||||
|
return this._memberEvent.content?.membership;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ import {EventKey} from "../EventKey.js";
|
|||||||
import {EventEntry} from "../entries/EventEntry.js";
|
import {EventEntry} from "../entries/EventEntry.js";
|
||||||
import {FragmentBoundaryEntry} from "../entries/FragmentBoundaryEntry.js";
|
import {FragmentBoundaryEntry} from "../entries/FragmentBoundaryEntry.js";
|
||||||
import {createEventEntry} from "./common.js";
|
import {createEventEntry} from "./common.js";
|
||||||
import {RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../members/RoomMember.js";
|
import {MemberChange, RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../members/RoomMember.js";
|
||||||
|
|
||||||
// Synapse bug? where the m.room.create event appears twice in sync response
|
// Synapse bug? where the m.room.create event appears twice in sync response
|
||||||
// when first syncing the room
|
// when first syncing the room
|
||||||
@ -102,13 +102,13 @@ export class SyncWriter {
|
|||||||
if (event.type === MEMBER_EVENT_TYPE) {
|
if (event.type === MEMBER_EVENT_TYPE) {
|
||||||
const userId = event.state_key;
|
const userId = event.state_key;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
const member = RoomMember.fromMemberEvent(this._roomId, event);
|
const memberChange = new MemberChange(this._roomId, event);
|
||||||
if (member) {
|
if (memberChange.member) {
|
||||||
// as this is sync, we can just replace the member
|
// as this is sync, we can just replace the member
|
||||||
// if it is there already
|
// if it is there already
|
||||||
txn.roomMembers.set(member.serialize());
|
txn.roomMembers.set(memberChange.member.serialize());
|
||||||
|
return memberChange;
|
||||||
}
|
}
|
||||||
return member;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
txn.roomState.set(this._roomId, event);
|
txn.roomState.set(this._roomId, event);
|
||||||
@ -116,22 +116,22 @@ export class SyncWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_writeStateEvents(roomResponse, txn) {
|
_writeStateEvents(roomResponse, txn) {
|
||||||
const changedMembers = [];
|
const memberChanges = new Map();
|
||||||
// persist state
|
// persist state
|
||||||
const {state} = roomResponse;
|
const {state} = roomResponse;
|
||||||
if (Array.isArray(state?.events)) {
|
if (Array.isArray(state?.events)) {
|
||||||
for (const event of state.events) {
|
for (const event of state.events) {
|
||||||
const member = this._writeStateEvent(event, txn);
|
const memberChange = this._writeStateEvent(event, txn);
|
||||||
if (member) {
|
if (memberChange) {
|
||||||
changedMembers.push(member);
|
memberChanges.set(memberChange.userId, memberChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return changedMembers;
|
return memberChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _writeTimeline(entries, timeline, currentKey, txn) {
|
async _writeTimeline(entries, timeline, currentKey, txn) {
|
||||||
const changedMembers = [];
|
const memberChanges = new Map();
|
||||||
if (timeline.events) {
|
if (timeline.events) {
|
||||||
const events = deduplicateEvents(timeline.events);
|
const events = deduplicateEvents(timeline.events);
|
||||||
for(const event of events) {
|
for(const event of events) {
|
||||||
@ -148,14 +148,14 @@ export class SyncWriter {
|
|||||||
|
|
||||||
// process live state events first, so new member info is available
|
// process live state events first, so new member info is available
|
||||||
if (typeof event.state_key === "string") {
|
if (typeof event.state_key === "string") {
|
||||||
const member = this._writeStateEvent(event, txn);
|
const memberChange = this._writeStateEvent(event, txn);
|
||||||
if (member) {
|
if (memberChange) {
|
||||||
changedMembers.push(member);
|
memberChanges.set(memberChange.userId, memberChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {currentKey, changedMembers};
|
return {currentKey, memberChanges};
|
||||||
}
|
}
|
||||||
|
|
||||||
async _findMemberData(userId, events, txn) {
|
async _findMemberData(userId, events, txn) {
|
||||||
@ -198,12 +198,14 @@ export class SyncWriter {
|
|||||||
}
|
}
|
||||||
// important this happens before _writeTimeline so
|
// important this happens before _writeTimeline so
|
||||||
// members are available in the transaction
|
// members are available in the transaction
|
||||||
const changedMembers = this._writeStateEvents(roomResponse, txn);
|
const memberChanges = this._writeStateEvents(roomResponse, txn);
|
||||||
const timelineResult = await this._writeTimeline(entries, timeline, currentKey, txn);
|
const timelineResult = await this._writeTimeline(entries, timeline, currentKey, txn);
|
||||||
currentKey = timelineResult.currentKey;
|
currentKey = timelineResult.currentKey;
|
||||||
changedMembers.push(...timelineResult.changedMembers);
|
// merge member changes from state and timeline, giving precedence to the latter
|
||||||
|
for (const [userId, memberChange] of timelineResult.memberChanges.entries()) {
|
||||||
return {entries, newLiveKey: currentKey, changedMembers};
|
memberChanges.set(userId, memberChange);
|
||||||
|
}
|
||||||
|
return {entries, newLiveKey: currentKey, memberChanges};
|
||||||
}
|
}
|
||||||
|
|
||||||
afterSync(newLiveKey) {
|
afterSync(newLiveKey) {
|
||||||
|
Loading…
Reference in New Issue
Block a user