update call member info with room member info

This commit is contained in:
Bruno Windels 2022-06-02 15:56:23 +02:00
parent a52740ed1b
commit 90b6a5ccb6
4 changed files with 53 additions and 18 deletions

View file

@ -117,7 +117,10 @@ class OwnMemberViewModel extends ViewModel<OwnMemberOptions> implements IStreamV
} }
} }
type MemberOptions = BaseOptions & {member: Member, mediaRepository: MediaRepository}; type MemberOptions = BaseOptions & {
member: Member,
mediaRepository: MediaRepository
};
export class CallMemberViewModel extends ViewModel<MemberOptions> implements IStreamViewModel { export class CallMemberViewModel extends ViewModel<MemberOptions> implements IStreamViewModel {
get stream(): Stream | undefined { get stream(): Stream | undefined {

View file

@ -22,6 +22,7 @@ import {EventType, CallIntent} from "./callEventTypes";
import {GroupCall} from "./group/GroupCall"; import {GroupCall} from "./group/GroupCall";
import {makeId} from "../common"; import {makeId} from "../common";
import {CALL_LOG_TYPE} from "./common"; import {CALL_LOG_TYPE} from "./common";
import {EVENT_TYPE as MEMBER_EVENT_TYPE, RoomMember} from "../room/members/RoomMember";
import type {LocalMedia} from "./LocalMedia"; import type {LocalMedia} from "./LocalMedia";
import type {Room} from "../room/Room"; import type {Room} from "../room/Room";
@ -36,6 +37,7 @@ import type {Transaction} from "../storage/idb/Transaction";
import type {CallEntry} from "../storage/idb/stores/CallStore"; import type {CallEntry} from "../storage/idb/stores/CallStore";
import type {Clock} from "../../platform/web/dom/Clock"; import type {Clock} from "../../platform/web/dom/Clock";
import type {RoomStateHandler} from "../room/state/types"; import type {RoomStateHandler} from "../room/state/types";
import type {MemberSync} from "../room/timeline/persistence/MemberWriter";
export type Options = Omit<GroupCallOptions, "emitUpdate" | "createTimeout"> & { export type Options = Omit<GroupCallOptions, "emitUpdate" | "createTimeout"> & {
clock: Clock clock: Clock
@ -77,7 +79,7 @@ export class CallHandler implements RoomStateHandler {
const names = this.options.storage.storeNames; const names = this.options.storage.storeNames;
const txn = await this.options.storage.readTxn([ const txn = await this.options.storage.readTxn([
names.calls, names.calls,
names.roomState names.roomState,
]); ]);
return txn; return txn;
} }
@ -97,15 +99,17 @@ export class CallHandler implements RoomStateHandler {
})); }));
const roomIds = Array.from(new Set(callEntries.map(e => e.roomId))); const roomIds = Array.from(new Set(callEntries.map(e => e.roomId)));
await Promise.all(roomIds.map(async roomId => { await Promise.all(roomIds.map(async roomId => {
// const ownCallsMemberEvent = await txn.roomState.get(roomId, EventType.GroupCallMember, this.options.ownUserId); // TODO: don't load all members until we need them
// if (ownCallsMemberEvent) {
// this.handleCallMemberEvent(ownCallsMemberEvent.event, log);
// }
const callsMemberEvents = await txn.roomState.getAllForType(roomId, EventType.GroupCallMember); const callsMemberEvents = await txn.roomState.getAllForType(roomId, EventType.GroupCallMember);
for (const entry of callsMemberEvents) { await Promise.all(callsMemberEvents.map(async entry => {
this.handleCallMemberEvent(entry.event, roomId, log); const roomMemberState = await txn.roomState.get(roomId, MEMBER_EVENT_TYPE, entry.event.sender);
if (roomMemberState) {
const roomMember = RoomMember.fromMemberEvent(roomMemberState.event);
if (roomMember) {
this.handleCallMemberEvent(entry.event, roomMember, roomId, log);
} }
// TODO: we should be loading the other members as well at some point }
}));
})); }));
log.set("newSize", this._calls.size); log.set("newSize", this._calls.size);
}); });
@ -144,12 +148,15 @@ export class CallHandler implements RoomStateHandler {
// TODO: check and poll turn server credentials here // TODO: check and poll turn server credentials here
/** @internal */ /** @internal */
handleRoomState(room: Room, event: StateEvent, txn: Transaction, log: ILogItem) { async handleRoomState(room: Room, event: StateEvent, memberSync: MemberSync, txn: Transaction, log: ILogItem) {
if (event.type === EventType.GroupCall) { if (event.type === EventType.GroupCall) {
this.handleCallEvent(event, room.id, txn, log); this.handleCallEvent(event, room.id, txn, log);
} }
if (event.type === EventType.GroupCallMember) { if (event.type === EventType.GroupCallMember) {
this.handleCallMemberEvent(event, room.id, log); const member: RoomMember | undefined = await memberSync.lookupMemberAtEvent(event.sender, event, txn);
if (member) { // should always have a member?
this.handleCallMemberEvent(event, member, room.id, log);
}
} }
} }
@ -157,6 +164,11 @@ export class CallHandler implements RoomStateHandler {
updateRoomMembers(room: Room, memberChanges: Map<string, MemberChange>) { updateRoomMembers(room: Room, memberChanges: Map<string, MemberChange>) {
// TODO: also have map for roomId to calls, so we can easily update members // TODO: also have map for roomId to calls, so we can easily update members
// we will also need this to get the call for a room // we will also need this to get the call for a room
for (const call of this._calls.values()) {
if (call.roomId === room.id) {
call.updateRoomMembers(memberChanges);
}
}
} }
/** @internal */ /** @internal */
@ -193,7 +205,7 @@ export class CallHandler implements RoomStateHandler {
} }
} }
private handleCallMemberEvent(event: StateEvent, roomId: string, log: ILogItem) { private handleCallMemberEvent(event: StateEvent, member: RoomMember, roomId: string, log: ILogItem) {
const userId = event.state_key; const userId = event.state_key;
const roomMemberKey = getRoomMemberKey(roomId, userId) const roomMemberKey = getRoomMemberKey(roomId, userId)
const calls = event.content["m.calls"] ?? []; const calls = event.content["m.calls"] ?? [];
@ -201,7 +213,7 @@ export class CallHandler implements RoomStateHandler {
const callId = call["m.call_id"]; const callId = call["m.call_id"];
const groupCall = this._calls.get(callId); const groupCall = this._calls.get(callId);
// TODO: also check the member when receiving the m.call event // TODO: also check the member when receiving the m.call event
groupCall?.updateMembership(userId, call, log); groupCall?.updateMembership(userId, member, call, log);
}; };
const newCallIdsMemberOf = new Set<string>(calls.map(call => call["m.call_id"])); const newCallIdsMemberOf = new Set<string>(calls.map(call => call["m.call_id"]));
let previousCallIdsMemberOf = this.roomMemberToCallIds.get(roomMemberKey); let previousCallIdsMemberOf = this.roomMemberToCallIds.get(roomMemberKey);

View file

@ -18,7 +18,7 @@ import {ObservableMap} from "../../../observable/map/ObservableMap";
import {Member} from "./Member"; import {Member} from "./Member";
import {LocalMedia} from "../LocalMedia"; import {LocalMedia} from "../LocalMedia";
import {MuteSettings, CALL_LOG_TYPE} from "../common"; import {MuteSettings, CALL_LOG_TYPE} from "../common";
import {RoomMember} from "../../room/members/RoomMember"; import {MemberChange, RoomMember} from "../../room/members/RoomMember";
import {EventEmitter} from "../../../utils/EventEmitter"; import {EventEmitter} from "../../../utils/EventEmitter";
import {EventType, CallIntent} from "../callEventTypes"; import {EventType, CallIntent} from "../callEventTypes";
@ -258,7 +258,20 @@ export class GroupCall extends EventEmitter<{change: never}> {
} }
/** @internal */ /** @internal */
updateMembership(userId: string, callMembership: CallMembership, syncLog: ILogItem) { updateRoomMembers(memberChanges: Map<string, MemberChange>) {
for (const change of memberChanges.values()) {
const {member} = change;
for (const callMember of this._members.values()) {
// find all call members for a room member (can be multiple, for every device)
if (callMember.userId === member.userId) {
callMember.updateRoomMember(member);
}
}
}
}
/** @internal */
updateMembership(userId: string, roomMember: RoomMember, callMembership: CallMembership, syncLog: ILogItem) {
syncLog.wrap({l: "update call membership", t: CALL_LOG_TYPE, id: this.id, userId}, log => { syncLog.wrap({l: "update call membership", t: CALL_LOG_TYPE, id: this.id, userId}, log => {
const devices = callMembership["m.devices"]; const devices = callMembership["m.devices"];
const previousDeviceIds = this.getDeviceIdsForUserId(userId); const previousDeviceIds = this.getDeviceIdsForUserId(userId);
@ -290,7 +303,7 @@ export class GroupCall extends EventEmitter<{change: never}> {
} }
log.set("add", true); log.set("add", true);
member = new Member( member = new Member(
RoomMember.fromUserId(this.roomId, userId, "join"), roomMember,
device, this._memberOptions, device, this._memberOptions,
); );
this._members.add(memberKey, member); this._members.add(memberKey, member);

View file

@ -68,7 +68,7 @@ export class Member {
private connection?: MemberConnection; private connection?: MemberConnection;
constructor( constructor(
public readonly member: RoomMember, public member: RoomMember,
private callDeviceMembership: CallDeviceMembership, private callDeviceMembership: CallDeviceMembership,
private readonly options: Options, private readonly options: Options,
) {} ) {}
@ -180,6 +180,13 @@ export class Member {
} }
} }
/** @internal */
updateRoomMember(roomMember: RoomMember) {
this.member = roomMember;
// TODO: this emits an update during the writeSync phase, which we usually try to avoid
this.options.emitUpdate(this);
}
/** @internal */ /** @internal */
emitUpdateFromPeerCall = (peerCall: PeerCall, params: any, log: ILogItem): void => { emitUpdateFromPeerCall = (peerCall: PeerCall, params: any, log: ILogItem): void => {
const connection = this.connection!; const connection = this.connection!;