add session.observeRoomState to observe state changes in all rooms
and use it for calls this won't be called for state already received and stored in storage, that you need to still do yourself
This commit is contained in:
parent
ec1568cf1c
commit
d727dfd843
6 changed files with 86 additions and 28 deletions
|
@ -15,11 +15,19 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {Logger} from "./logging/Logger";
|
export {Logger} from "./logging/Logger";
|
||||||
|
export type {ILogItem} from "./logging/types";
|
||||||
export {IDBLogPersister} from "./logging/IDBLogPersister";
|
export {IDBLogPersister} from "./logging/IDBLogPersister";
|
||||||
export {ConsoleReporter} from "./logging/ConsoleReporter";
|
export {ConsoleReporter} from "./logging/ConsoleReporter";
|
||||||
export {Platform} from "./platform/web/Platform.js";
|
export {Platform} from "./platform/web/Platform.js";
|
||||||
export {Client, LoadStatus} from "./matrix/Client.js";
|
export {Client, LoadStatus} from "./matrix/Client.js";
|
||||||
export {RoomStatus} from "./matrix/room/common";
|
export {RoomStatus} from "./matrix/room/common";
|
||||||
|
// export everything needed to observe state events on all rooms using session.observeRoomState
|
||||||
|
export type {RoomStateHandler} from "./matrix/room/common";
|
||||||
|
export type {MemberChange} from "./matrix/room/members/RoomMember";
|
||||||
|
export type {Transaction} from "./matrix/storage/idb/Transaction";
|
||||||
|
export type {Room} from "./matrix/room/Room";
|
||||||
|
export type {StateEvent} from "./matrix/storage/types";
|
||||||
|
|
||||||
// export main view & view models
|
// export main view & view models
|
||||||
export {createNavigation, createRouter} from "./domain/navigation/index.js";
|
export {createNavigation, createRouter} from "./domain/navigation/index.js";
|
||||||
export {RootViewModel} from "./domain/RootViewModel.js";
|
export {RootViewModel} from "./domain/RootViewModel.js";
|
||||||
|
|
37
src/matrix/RoomStateHandlerSet.ts
Normal file
37
src/matrix/RoomStateHandlerSet.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {ILogItem} from "../logging/types";
|
||||||
|
import type {StateEvent} from "./storage/types";
|
||||||
|
import type {Transaction} from "./storage/idb/Transaction";
|
||||||
|
import type {Room} from "./room/Room";
|
||||||
|
import type {MemberChange} from "./room/members/RoomMember";
|
||||||
|
import type {RoomStateHandler} from "./room/common";
|
||||||
|
import {BaseObservable} from "../observable/BaseObservable";
|
||||||
|
|
||||||
|
/** keeps track of all handlers registered with Session.observeRoomState */
|
||||||
|
export class RoomStateHandlerSet extends BaseObservable<RoomStateHandler> implements RoomStateHandler {
|
||||||
|
handleRoomState(room: Room, stateEvent: StateEvent, txn: Transaction, log: ILogItem) {
|
||||||
|
for(let h of this._handlers) {
|
||||||
|
h.handleRoomState(room, stateEvent, txn, log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateRoomMembers(room: Room, memberChanges: Map<string, MemberChange>) {
|
||||||
|
for(let h of this._handlers) {
|
||||||
|
h.updateRoomMembers(room, memberChanges);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ import {SecretStorage} from "./ssss/SecretStorage";
|
||||||
import {ObservableValue} from "../observable/value/ObservableValue";
|
import {ObservableValue} from "../observable/value/ObservableValue";
|
||||||
import {RetainedObservableValue} from "../observable/value/RetainedObservableValue";
|
import {RetainedObservableValue} from "../observable/value/RetainedObservableValue";
|
||||||
import {CallHandler} from "./calls/CallHandler";
|
import {CallHandler} from "./calls/CallHandler";
|
||||||
|
import {RoomStateHandlerSet} from "./RoomStateHandlerSet";
|
||||||
|
|
||||||
const PICKLE_KEY = "DEFAULT_KEY";
|
const PICKLE_KEY = "DEFAULT_KEY";
|
||||||
const PUSHER_KEY = "pusher";
|
const PUSHER_KEY = "pusher";
|
||||||
|
@ -101,6 +102,8 @@ export class Session {
|
||||||
}],
|
}],
|
||||||
forceTURN: false,
|
forceTURN: false,
|
||||||
});
|
});
|
||||||
|
this._roomStateHandler = new RoomStateHandlerSet();
|
||||||
|
this.observeRoomState(this._callHandler);
|
||||||
this._deviceMessageHandler = new DeviceMessageHandler({storage, callHandler: this._callHandler});
|
this._deviceMessageHandler = new DeviceMessageHandler({storage, callHandler: this._callHandler});
|
||||||
this._olm = olm;
|
this._olm = olm;
|
||||||
this._olmUtil = null;
|
this._olmUtil = null;
|
||||||
|
@ -595,7 +598,7 @@ export class Session {
|
||||||
user: this._user,
|
user: this._user,
|
||||||
createRoomEncryption: this._createRoomEncryption,
|
createRoomEncryption: this._createRoomEncryption,
|
||||||
platform: this._platform,
|
platform: this._platform,
|
||||||
callHandler: this._callHandler
|
roomStateHandler: this._roomStateHandler
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -937,6 +940,10 @@ export class Session {
|
||||||
return observable;
|
return observable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observeRoomState(roomStateHandler) {
|
||||||
|
return this._roomStateHandler.subscribe(roomStateHandler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates an empty (summary isn't loaded) the archived room if it isn't
|
Creates an empty (summary isn't loaded) the archived room if it isn't
|
||||||
loaded already, assuming sync will either remove it (when rejoining) or
|
loaded already, assuming sync will either remove it (when rejoining) or
|
||||||
|
|
|
@ -35,6 +35,7 @@ import type {Options as GroupCallOptions} from "./group/GroupCall";
|
||||||
import type {Transaction} from "../storage/idb/Transaction";
|
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/common";
|
||||||
|
|
||||||
export type Options = Omit<GroupCallOptions, "emitUpdate" | "createTimeout"> & {
|
export type Options = Omit<GroupCallOptions, "emitUpdate" | "createTimeout"> & {
|
||||||
clock: Clock
|
clock: Clock
|
||||||
|
@ -44,7 +45,7 @@ function getRoomMemberKey(roomId: string, userId: string): string {
|
||||||
return JSON.stringify(roomId)+`,`+JSON.stringify(userId);
|
return JSON.stringify(roomId)+`,`+JSON.stringify(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CallHandler {
|
export class CallHandler implements RoomStateHandler {
|
||||||
// group calls by call id
|
// group calls by call id
|
||||||
private readonly _calls: ObservableMap<string, GroupCall> = new ObservableMap<string, GroupCall>();
|
private readonly _calls: ObservableMap<string, GroupCall> = new ObservableMap<string, GroupCall>();
|
||||||
// map of `"roomId","userId"` to set of conf_id's they are in
|
// map of `"roomId","userId"` to set of conf_id's they are in
|
||||||
|
@ -143,20 +144,14 @@ export class CallHandler {
|
||||||
// TODO: check and poll turn server credentials here
|
// TODO: check and poll turn server credentials here
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
handleRoomState(room: Room, events: StateEvent[], txn: Transaction, log: ILogItem) {
|
handleRoomState(room: Room, event: StateEvent, txn: Transaction, log: ILogItem) {
|
||||||
// first update call events
|
|
||||||
for (const event of events) {
|
|
||||||
if (event.type === EventType.GroupCall) {
|
if (event.type === EventType.GroupCall) {
|
||||||
this.handleCallEvent(event, room.id, txn, log);
|
this.handleCallEvent(event, room.id, txn, log);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// then update members
|
|
||||||
for (const event of events) {
|
|
||||||
if (event.type === EventType.GroupCallMember) {
|
if (event.type === EventType.GroupCallMember) {
|
||||||
this.handleCallMemberEvent(event, room.id, log);
|
this.handleCallMemberEvent(event, room.id, log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
updateRoomMembers(room: Room, memberChanges: Map<string, MemberChange>) {
|
updateRoomMembers(room: Room, memberChanges: Map<string, MemberChange>) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ const EVENT_ENCRYPTED_TYPE = "m.room.encrypted";
|
||||||
export class Room extends BaseRoom {
|
export class Room extends BaseRoom {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
super(options);
|
super(options);
|
||||||
this._callHandler = options.callHandler;
|
this._roomStateHandler = options.roomStateHandler;
|
||||||
// TODO: pass pendingEvents to start like pendingOperations?
|
// TODO: pass pendingEvents to start like pendingOperations?
|
||||||
const {pendingEvents} = options;
|
const {pendingEvents} = options;
|
||||||
const relationWriter = new RelationWriter({
|
const relationWriter = new RelationWriter({
|
||||||
|
@ -179,7 +179,7 @@ export class Room extends BaseRoom {
|
||||||
removedPendingEvents = await this._sendQueue.removeRemoteEchos(roomResponse.timeline.events, txn, log);
|
removedPendingEvents = await this._sendQueue.removeRemoteEchos(roomResponse.timeline.events, txn, log);
|
||||||
}
|
}
|
||||||
const powerLevelsEvent = this._getPowerLevelsEvent(roomResponse);
|
const powerLevelsEvent = this._getPowerLevelsEvent(roomResponse);
|
||||||
this._updateCallHandler(roomResponse, txn, log);
|
this._updateRoomStateHandler(roomResponse, txn, log);
|
||||||
return {
|
return {
|
||||||
summaryChanges,
|
summaryChanges,
|
||||||
roomEncryption,
|
roomEncryption,
|
||||||
|
@ -217,9 +217,7 @@ export class Room extends BaseRoom {
|
||||||
if (this._memberList) {
|
if (this._memberList) {
|
||||||
this._memberList.afterSync(memberChanges);
|
this._memberList.afterSync(memberChanges);
|
||||||
}
|
}
|
||||||
if (this._callHandler) {
|
this._roomStateHandler.updateRoomMembers(this, memberChanges);
|
||||||
this._callHandler.updateRoomMembers(this, memberChanges);
|
|
||||||
}
|
|
||||||
if (this._observedMembers) {
|
if (this._observedMembers) {
|
||||||
this._updateObservedMembers(memberChanges);
|
this._updateObservedMembers(memberChanges);
|
||||||
}
|
}
|
||||||
|
@ -447,17 +445,19 @@ export class Room extends BaseRoom {
|
||||||
return this._sendQueue.pendingEvents;
|
return this._sendQueue.pendingEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateCallHandler(roomResponse, txn, log) {
|
_updateRoomStateHandler(roomResponse, txn, log) {
|
||||||
if (this._callHandler) {
|
|
||||||
const stateEvents = roomResponse.state?.events;
|
const stateEvents = roomResponse.state?.events;
|
||||||
if (stateEvents?.length) {
|
if (stateEvents) {
|
||||||
this._callHandler.handleRoomState(this, stateEvents, txn, log);
|
for (let i = 0; i < stateEvents.length; i++) {
|
||||||
|
this._roomStateHandler.handleRoomState(this, stateEvents[i], txn, log);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let timelineEvents = roomResponse.timeline?.events;
|
let timelineEvents = roomResponse.timeline?.events;
|
||||||
if (timelineEvents) {
|
if (timelineEvents) {
|
||||||
const timelineStateEvents = timelineEvents.filter(e => typeof e.state_key === "string");
|
for (let i = 0; i < timelineEvents.length; i++) {
|
||||||
if (timelineEvents.length !== 0) {
|
const event = timelineEvents[i];
|
||||||
this._callHandler.handleRoomState(this, timelineStateEvents, txn, log);
|
if (typeof event.state_key === "string") {
|
||||||
|
this._roomStateHandler.handleRoomState(this, event, txn, log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,12 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type {Room} from "./Room";
|
||||||
|
import type {StateEvent} from "../storage/types";
|
||||||
|
import type {Transaction} from "../storage/idb/Transaction";
|
||||||
|
import type {ILogItem} from "../../logging/types";
|
||||||
|
import type {MemberChange} from "./members/RoomMember";
|
||||||
|
|
||||||
export function getPrevContentFromStateEvent(event) {
|
export function getPrevContentFromStateEvent(event) {
|
||||||
// where to look for prev_content is a bit of a mess,
|
// where to look for prev_content is a bit of a mess,
|
||||||
// see https://matrix.to/#/!NasysSDfxKxZBzJJoE:matrix.org/$DvrAbZJiILkOmOIuRsNoHmh2v7UO5CWp_rYhlGk34fQ?via=matrix.org&via=pixie.town&via=amorgan.xyz
|
// see https://matrix.to/#/!NasysSDfxKxZBzJJoE:matrix.org/$DvrAbZJiILkOmOIuRsNoHmh2v7UO5CWp_rYhlGk34fQ?via=matrix.org&via=pixie.town&via=amorgan.xyz
|
||||||
|
@ -40,3 +46,8 @@ export enum RoomType {
|
||||||
Private,
|
Private,
|
||||||
Public
|
Public
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RoomStateHandler {
|
||||||
|
handleRoomState(room: Room, stateEvent: StateEvent, txn: Transaction, log: ILogItem);
|
||||||
|
updateRoomMembers(room: Room, memberChanges: Map<string, MemberChange>);
|
||||||
|
}
|
||||||
|
|
Reference in a new issue