Files
element-call/src/home/useGroupCallRooms.ts
T

154 lines
4.6 KiB
TypeScript
Raw Normal View History

2022-05-04 17:09:48 +01:00
/*
2023-01-03 16:55:26 +00:00
Copyright 2022 New Vector Ltd
2022-05-04 17:09:48 +01:00
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.
*/
2022-08-12 16:46:53 -04:00
import { MatrixClient } from "matrix-js-sdk/src/client";
2024-04-23 15:15:13 +02:00
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
2022-08-12 16:46:53 -04:00
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
2022-01-05 17:19:03 -08:00
import { useState, useEffect } from "react";
2024-04-23 15:15:13 +02:00
import { EventTimeline, EventType, JoinRule } from "matrix-js-sdk";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { MatrixRTCSessionManagerEvents } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSessionManager";
import { KnownMembership } from "matrix-js-sdk/src/types";
2022-01-05 17:19:03 -08:00
2024-04-23 15:15:13 +02:00
import { getKeyForRoom } from "../e2ee/sharedKeyManagement";
2022-07-14 19:20:52 +02:00
export interface GroupCallRoom {
2023-09-19 19:23:19 +01:00
roomAlias?: string;
2022-07-14 19:20:52 +02:00
roomName: string;
avatarUrl: string;
room: Room;
2024-04-23 15:15:13 +02:00
session: MatrixRTCSession;
2022-07-14 19:20:52 +02:00
participants: RoomMember[];
}
const tsCache: { [index: string]: number } = {};
2022-01-05 17:19:03 -08:00
2023-09-22 18:05:13 -04:00
function getLastTs(client: MatrixClient, r: Room): number {
2022-01-05 17:19:03 -08:00
if (tsCache[r.roomId]) {
return tsCache[r.roomId];
}
if (!r || !r.timeline) {
const ts = Number.MAX_SAFE_INTEGER;
tsCache[r.roomId] = ts;
return ts;
}
2023-06-30 16:43:28 +01:00
const myUserId = client.getUserId()!;
2022-01-05 17:19:03 -08:00
2024-04-23 15:15:13 +02:00
if (r.getMyMembership() !== KnownMembership.Join) {
2022-01-05 17:19:03 -08:00
const membershipEvent = r.currentState.getStateEvents(
"m.room.member",
2023-10-11 10:42:04 -04:00
myUserId,
2022-01-05 17:19:03 -08:00
);
if (membershipEvent && !Array.isArray(membershipEvent)) {
const ts = membershipEvent.getTs();
tsCache[r.roomId] = ts;
return ts;
}
}
for (let i = r.timeline.length - 1; i >= 0; --i) {
const ev = r.timeline[i];
const ts = ev.getTs();
if (ts) {
tsCache[r.roomId] = ts;
return ts;
}
}
const ts = Number.MAX_SAFE_INTEGER;
tsCache[r.roomId] = ts;
return ts;
}
2022-07-14 19:20:52 +02:00
function sortRooms(client: MatrixClient, rooms: Room[]): Room[] {
2022-01-05 17:19:03 -08:00
return rooms.sort((a, b) => {
return getLastTs(client, b) - getLastTs(client, a);
});
}
2024-04-23 15:15:13 +02:00
const roomIsJoinable = (room: Room): boolean => {
if (!room.hasEncryptionStateEvent() && !getKeyForRoom(room.roomId)) {
// if we have an non encrypted room (no encryption state event) we need a locally stored shared key.
// in case this key also does not exists we cannot join the room.
return false;
}
2024-04-23 15:15:13 +02:00
// otherwise we can always join rooms because we will automatically decide if we want to use perParticipant or password
const joinRule = room.getJoinRule();
return joinRule === JoinRule.Knock || joinRule === JoinRule.Public;
};
const roomHasCallMembershipEvents = (room: Room): boolean => {
const roomStateEvents = room
.getLiveTimeline()
.getState(EventTimeline.FORWARDS)?.events;
return (
room.getMyMembership() === KnownMembership.Join &&
!!roomStateEvents?.get(EventType.GroupCallMemberPrefix)
);
};
2022-07-14 19:20:52 +02:00
export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] {
2023-07-03 19:23:26 +02:00
const [rooms, setRooms] = useState<GroupCallRoom[]>([]);
2022-01-05 17:19:03 -08:00
useEffect(() => {
2023-09-22 18:05:13 -04:00
function updateRooms(): void {
2024-04-23 15:15:13 +02:00
// We want to show all rooms that historically had a call and which we are (can become) part of.
const rooms = client
.getRooms()
.filter(roomHasCallMembershipEvents)
.filter(roomIsJoinable);
2023-08-11 13:25:09 +02:00
const sortedRooms = sortRooms(client, rooms);
2022-01-05 17:19:03 -08:00
const items = sortedRooms.map((room) => {
2024-04-23 15:15:13 +02:00
const session = client.matrixRTC.getRoomSession(room);
session.memberships;
2022-01-05 17:19:03 -08:00
return {
2023-09-19 19:23:19 +01:00
roomAlias: room.getCanonicalAlias() ?? undefined,
2022-01-05 17:19:03 -08:00
roomName: room.name,
2023-06-30 16:43:28 +01:00
avatarUrl: room.getMxcAvatarUrl()!,
2022-01-05 17:19:03 -08:00
room,
2024-04-23 15:15:13 +02:00
session,
participants: session.memberships
.filter((m) => m.sender)
.map((m) => room.getMember(m.sender!))
.filter((m) => m) as RoomMember[],
2022-01-05 17:19:03 -08:00
};
});
2023-06-30 16:43:28 +01:00
2023-09-19 19:23:19 +01:00
setRooms(items);
2022-01-05 17:19:03 -08:00
}
updateRooms();
2024-04-23 15:15:13 +02:00
client.matrixRTC.on(
MatrixRTCSessionManagerEvents.SessionStarted,
updateRooms,
);
client.on(RoomEvent.MyMembership, updateRooms);
2022-01-05 17:19:03 -08:00
return () => {
2024-04-23 15:15:13 +02:00
client.matrixRTC.off(
MatrixRTCSessionManagerEvents.SessionStarted,
2023-10-11 10:42:04 -04:00
updateRooms,
2022-07-14 19:20:52 +02:00
);
2024-04-23 15:15:13 +02:00
client.off(RoomEvent.MyMembership, updateRooms);
2022-01-05 17:19:03 -08:00
};
2022-05-05 13:15:07 +01:00
}, [client]);
2022-01-05 17:19:03 -08:00
return rooms;
}