backend: update room retrieval to use selective fields for efficiency
This commit is contained in:
parent
37023fe077
commit
2572fd3960
@ -15,7 +15,7 @@ export const endMeeting = async (req: Request, res: Response) => {
|
||||
|
||||
// Check if the room exists
|
||||
try {
|
||||
await roomService.getMeetRoom(roomId);
|
||||
await roomService.getMeetRoom(roomId, ['roomId']);
|
||||
} catch (error) {
|
||||
return handleError(res, error, `getting room '${roomId}'`);
|
||||
}
|
||||
@ -53,7 +53,7 @@ export const kickParticipantFromMeeting = async (req: Request, res: Response) =>
|
||||
|
||||
// Check if the room exists
|
||||
try {
|
||||
await roomService.getMeetRoom(roomId);
|
||||
await roomService.getMeetRoom(roomId, ['roomId']);
|
||||
} catch (error) {
|
||||
return handleError(res, error, `getting room '${roomId}'`);
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ export class RecordingHelper {
|
||||
const layout = RecordingHelper.extractRecordingLayout(egressInfo);
|
||||
const encoding = RecordingHelper.extractRecordingEncoding(egressInfo);
|
||||
const roomService = container.get(RoomService);
|
||||
const { roomName } = await roomService.getMeetRoom(roomId);
|
||||
const { roomName } = await roomService.getMeetRoom(roomId, ['roomName']);
|
||||
|
||||
return {
|
||||
recordingId,
|
||||
|
||||
@ -2,6 +2,7 @@ import {
|
||||
MEET_ROOM_EXTRA_FIELDS,
|
||||
MEET_ROOM_FIELDS,
|
||||
MeetRoom,
|
||||
MeetRoomAnonymous,
|
||||
MeetRoomExtraField,
|
||||
MeetRoomField,
|
||||
MeetRoomMemberPermissions,
|
||||
@ -89,19 +90,19 @@ export class MeetRoomHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts speaker and moderator secrets from a MeetRoom object's URLs.
|
||||
* Extracts speaker and moderator secrets from MeetRoom anonymous access URLs.
|
||||
*
|
||||
* This method parses the 'secret' query parameter from both speaker and moderator
|
||||
* anonymous access URLs associated with the meeting room.
|
||||
*
|
||||
* @param room - The MeetRoom object containing speakerUrl and moderatorUrl properties
|
||||
* @param room - The anonymous access configuration of the MeetRoom from which to extract secrets.
|
||||
* @returns An object containing the extracted secrets with the following properties:
|
||||
* - speakerSecret: The secret extracted from the speaker anonymous access URL
|
||||
* - moderatorSecret: The secret extracted from the moderator anonymous access URL
|
||||
*/
|
||||
static extractSecretsFromRoom(room: MeetRoom): { speakerSecret: string; moderatorSecret: string } {
|
||||
const speakerUrl = room.anonymous.speaker.accessUrl;
|
||||
const moderatorUrl = room.anonymous.moderator.accessUrl;
|
||||
static extractSecretsFromRoom(anonymous: MeetRoomAnonymous): { speakerSecret: string; moderatorSecret: string } {
|
||||
const speakerUrl = anonymous.speaker.accessUrl;
|
||||
const moderatorUrl = anonymous.moderator.accessUrl;
|
||||
|
||||
const parsedSpeakerUrl = new URL(speakerUrl);
|
||||
const speakerSecret = parsedSpeakerUrl.searchParams.get('secret') || '';
|
||||
|
||||
@ -28,9 +28,9 @@ export const withRecordingEnabled = async (req: Request, res: Response, next: Ne
|
||||
|
||||
try {
|
||||
const { roomId } = req.body as { roomId: string };
|
||||
const room = await roomService.getMeetRoom(roomId!);
|
||||
const { config } = await roomService.getMeetRoom(roomId!, ['config']);
|
||||
|
||||
if (!room.config.recording.enabled) {
|
||||
if (!config.recording.enabled) {
|
||||
logger.debug(`Recording is disabled for room '${roomId}'`);
|
||||
const error = errorRecordingDisabled(roomId!);
|
||||
return rejectRequestFromMeetError(res, error);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {
|
||||
MeetRecordingConfig,
|
||||
MeetRecordingEncodingOptions,
|
||||
MeetRecordingEncodingPreset,
|
||||
MeetRecordingField,
|
||||
@ -6,8 +7,6 @@ import {
|
||||
MeetRecordingInfo,
|
||||
MeetRecordingLayout,
|
||||
MeetRecordingStatus,
|
||||
MeetRoom,
|
||||
MeetRoomConfig,
|
||||
MeetRoomMemberPermissions
|
||||
} from '@openvidu-meet/typings';
|
||||
import { inject, injectable } from 'inversify';
|
||||
@ -86,7 +85,7 @@ export class RecordingService {
|
||||
|
||||
if (!acquiredLock) throw errorRecordingAlreadyStarted(roomId);
|
||||
|
||||
const room = await this.validateRoomForStartRecording(roomId);
|
||||
const roomRecordingConfig = await this.validateRoomForStartRecording(roomId);
|
||||
|
||||
// Manually send the recording signal to OpenVidu Components for avoiding missing event if timeout occurs
|
||||
// and the egress_started webhook is not received.
|
||||
@ -131,7 +130,7 @@ export class RecordingService {
|
||||
// Promise that starts the recording process
|
||||
const startRecordingPromise = (async (): Promise<MeetRecordingInfo> => {
|
||||
try {
|
||||
const options = this.generateCompositeOptionsFromRequest(room.config, configOverride);
|
||||
const options = this.generateCompositeOptionsFromRequest(roomRecordingConfig, configOverride);
|
||||
const output = this.generateFileOutputFromRequest(roomId);
|
||||
const egressInfo = await this.livekitService.startRoomComposite(roomId, output, options);
|
||||
|
||||
@ -592,18 +591,18 @@ export class RecordingService {
|
||||
* Validates that a room exists and has participants before starting a recording.
|
||||
*
|
||||
* @param roomId
|
||||
* @returns The MeetRoom object if validation passes.
|
||||
* @returns The MeetRecordingConfig object if validation passes.
|
||||
* @throws Will throw an error if the room does not exist or has no participants.
|
||||
*/
|
||||
protected async validateRoomForStartRecording(roomId: string): Promise<MeetRoom> {
|
||||
protected async validateRoomForStartRecording(roomId: string): Promise<MeetRecordingConfig> {
|
||||
const roomService = await this.getRoomService();
|
||||
const room = await roomService.getMeetRoom(roomId);
|
||||
const { config } = await roomService.getMeetRoom(roomId, ['config']);
|
||||
|
||||
const hasParticipants = await this.livekitService.roomHasParticipants(roomId);
|
||||
|
||||
if (!hasParticipants) throw errorRoomHasNoParticipants(roomId);
|
||||
|
||||
return room;
|
||||
return config.recording;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -738,21 +737,20 @@ export class RecordingService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates composite options for recording based on the provided room configuration.
|
||||
* Generates composite options for recording based on the provided room recording configuration.
|
||||
* If configOverride is provided, its values will take precedence over room configuration.
|
||||
*
|
||||
* @param roomConfig The room configuration
|
||||
* @param roomRecordingConfig The recording configuration defined for the room
|
||||
* @param configOverride Optional configuration override from the request
|
||||
* @returns The generated RoomCompositeOptions object.
|
||||
*/
|
||||
protected generateCompositeOptionsFromRequest(
|
||||
roomConfig: MeetRoomConfig,
|
||||
roomRecordingConfig: MeetRecordingConfig,
|
||||
configOverride?: {
|
||||
layout?: MeetRecordingLayout;
|
||||
encoding?: MeetRecordingEncodingPreset | MeetRecordingEncodingOptions;
|
||||
}
|
||||
): RoomCompositeOptions {
|
||||
const roomRecordingConfig = roomConfig.recording;
|
||||
const layout = configOverride?.layout ?? roomRecordingConfig.layout;
|
||||
const encoding = configOverride?.encoding ?? roomRecordingConfig.encoding;
|
||||
const encodingOptions = EncodingConverter.toLivekit(encoding);
|
||||
|
||||
@ -109,8 +109,8 @@ export class RoomMemberService {
|
||||
}
|
||||
|
||||
// Compute effective permissions
|
||||
const room = await this.roomService.getMeetRoom(roomId, ['roles']);
|
||||
const effectivePermissions = this.computeEffectivePermissions(room.roles, baseRole, customPermissions);
|
||||
const { roles } = await this.roomService.getMeetRoom(roomId, ['roles']);
|
||||
const effectivePermissions = this.computeEffectivePermissions(roles, baseRole, customPermissions);
|
||||
|
||||
const now = Date.now();
|
||||
const roomMember = {
|
||||
@ -219,9 +219,9 @@ export class RoomMemberService {
|
||||
}
|
||||
|
||||
// Recompute effective permissions
|
||||
const room = await this.roomService.getMeetRoom(roomId, ['roles']);
|
||||
const { roles } = await this.roomService.getMeetRoom(roomId, ['roles']);
|
||||
member.effectivePermissions = this.computeEffectivePermissions(
|
||||
room.roles,
|
||||
roles,
|
||||
member.baseRole,
|
||||
member.customPermissions
|
||||
);
|
||||
@ -419,14 +419,14 @@ export class RoomMemberService {
|
||||
} else {
|
||||
// If secret matches anonymous access URL secret, assign role and permissions based on it
|
||||
baseRole = await this.getRoomMemberRoleBySecret(roomId, secret);
|
||||
const room = await this.roomService.getMeetRoom(roomId, ['roles', 'anonymous']);
|
||||
const { roles, anonymous } = await this.roomService.getMeetRoom(roomId, ['roles', 'anonymous']);
|
||||
|
||||
// Check that anonymous access is enabled for the role
|
||||
if (!room.anonymous[baseRole].enabled) {
|
||||
if (!anonymous[baseRole].enabled) {
|
||||
throw errorAnonymousAccessDisabled(roomId, baseRole);
|
||||
}
|
||||
|
||||
effectivePermissions = room.roles[baseRole].permissions;
|
||||
effectivePermissions = roles[baseRole].permissions;
|
||||
}
|
||||
} else {
|
||||
// Case 2: Authenticated user
|
||||
@ -491,9 +491,9 @@ export class RoomMemberService {
|
||||
userId?: string
|
||||
): Promise<string> {
|
||||
// Check that room is open
|
||||
const room = await this.roomService.getMeetRoom(roomId, ['status', 'config']);
|
||||
const { status, config } = await this.roomService.getMeetRoom(roomId, ['status', 'config']);
|
||||
|
||||
if (room.status === MeetRoomStatus.CLOSED) {
|
||||
if (status === MeetRoomStatus.CLOSED) {
|
||||
throw errorRoomClosed(roomId);
|
||||
}
|
||||
|
||||
@ -557,7 +557,7 @@ export class RoomMemberService {
|
||||
customPermissions,
|
||||
effectivePermissions
|
||||
};
|
||||
const roomWithCaptions = room.config.captions.enabled;
|
||||
const roomWithCaptions = config.captions.enabled;
|
||||
|
||||
// Generate token with participant name
|
||||
return this.tokenService.generateRoomMemberToken({
|
||||
@ -610,8 +610,8 @@ export class RoomMemberService {
|
||||
* @throws Error if the provided secret doesn't match any of the room's secrets (unauthorized)
|
||||
*/
|
||||
protected async getRoomMemberRoleBySecret(roomId: string, secret: string): Promise<MeetRoomMemberRole> {
|
||||
const room = await this.roomService.getMeetRoom(roomId, ['roomId', 'anonymous']);
|
||||
const { moderatorSecret, speakerSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||
const { anonymous } = await this.roomService.getMeetRoom(roomId, ['anonymous']);
|
||||
const { moderatorSecret, speakerSecret } = MeetRoomHelper.extractSecretsFromRoom(anonymous);
|
||||
|
||||
switch (secret) {
|
||||
case moderatorSecret:
|
||||
@ -619,7 +619,7 @@ export class RoomMemberService {
|
||||
case speakerSecret:
|
||||
return MeetRoomMemberRole.SPEAKER;
|
||||
default:
|
||||
throw errorInvalidRoomSecret(room.roomId, secret);
|
||||
throw errorInvalidRoomSecret(roomId, secret);
|
||||
}
|
||||
}
|
||||
|
||||
@ -779,7 +779,7 @@ export class RoomMemberService {
|
||||
newRole: MeetRoomMemberRole
|
||||
): Promise<void> {
|
||||
try {
|
||||
const meetRoom = await this.roomService.getMeetRoom(roomId, ['roles', 'anonymous']);
|
||||
const { roles, anonymous } = await this.roomService.getMeetRoom(roomId, ['roles', 'anonymous']);
|
||||
const participant = await this.getParticipantFromMeeting(roomId, participantIdentity);
|
||||
const metadata: MeetRoomMemberTokenMetadata = this.tokenService.parseRoomMemberTokenMetadata(
|
||||
participant.metadata
|
||||
@ -788,11 +788,11 @@ export class RoomMemberService {
|
||||
// Update role and permissions in metadata
|
||||
metadata.baseRole = newRole;
|
||||
metadata.customPermissions = undefined;
|
||||
metadata.effectivePermissions = meetRoom.roles[newRole].permissions;
|
||||
metadata.effectivePermissions = roles[newRole].permissions;
|
||||
|
||||
await this.livekitService.updateParticipantMetadata(roomId, participantIdentity, JSON.stringify(metadata));
|
||||
|
||||
const { speakerSecret, moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(meetRoom);
|
||||
const { speakerSecret, moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(anonymous);
|
||||
const secret = newRole === MeetRoomMemberRole.MODERATOR ? moderatorSecret : speakerSecret;
|
||||
await this.frontendEventService.sendParticipantRoleUpdatedSignal(
|
||||
roomId,
|
||||
|
||||
@ -313,7 +313,7 @@ export class RoomService {
|
||||
* @returns A Promise that resolves to true if the room exists, false otherwise
|
||||
*/
|
||||
async meetRoomExists(roomId: string): Promise<boolean> {
|
||||
const meetRoom = await this.roomRepository.findByRoomId(roomId);
|
||||
const meetRoom = await this.roomRepository.findByRoomId(roomId, ['roomId']);
|
||||
return !!meetRoom;
|
||||
}
|
||||
|
||||
@ -857,8 +857,8 @@ export class RoomService {
|
||||
* @throws Error if room not found
|
||||
*/
|
||||
async isRoomOwner(roomId: string, userId: string): Promise<boolean> {
|
||||
const room = await this.getMeetRoom(roomId, ['owner']);
|
||||
return room.owner === userId;
|
||||
const { owner } = await this.getMeetRoom(roomId, ['owner']);
|
||||
return owner === userId;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -870,8 +870,8 @@ export class RoomService {
|
||||
* @throws Error if room not found
|
||||
*/
|
||||
async isValidRoomSecret(roomId: string, secret: string): Promise<boolean> {
|
||||
const room = await this.getMeetRoom(roomId, ['anonymous']);
|
||||
const { moderatorSecret, speakerSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||
const { anonymous } = await this.getMeetRoom(roomId, ['anonymous']);
|
||||
const { moderatorSecret, speakerSecret } = MeetRoomHelper.extractSecretsFromRoom(anonymous);
|
||||
return secret === moderatorSecret || secret === speakerSecret;
|
||||
}
|
||||
|
||||
@ -934,7 +934,7 @@ export class RoomService {
|
||||
*/
|
||||
async canUserAccessRoom(roomId: string, user: MeetUser): Promise<boolean> {
|
||||
// Verify room exists first (throws 404 if not found)
|
||||
const room = await this.getMeetRoom(roomId, ['owner']);
|
||||
const { owner } = await this.getMeetRoom(roomId, ['owner']);
|
||||
|
||||
if (user.role === MeetUserRole.ADMIN) {
|
||||
// Admins can access all rooms
|
||||
@ -942,7 +942,7 @@ export class RoomService {
|
||||
}
|
||||
|
||||
// Users can access rooms they own or are members of
|
||||
const isOwner = room.owner === user.userId;
|
||||
const isOwner = owner === user.userId;
|
||||
|
||||
if (isOwner) {
|
||||
return true;
|
||||
|
||||
@ -51,7 +51,7 @@ export const setupSingleRoom = async (
|
||||
});
|
||||
|
||||
// Extract the room secrets and generate room member tokens
|
||||
const { moderatorSecret, speakerSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||
const { moderatorSecret, speakerSecret } = MeetRoomHelper.extractSecretsFromRoom(room.anonymous);
|
||||
const [moderatorToken, speakerToken] = await Promise.all([
|
||||
generateRoomMemberToken(room.roomId, { secret: moderatorSecret, joinMeeting: false }),
|
||||
generateRoomMemberToken(room.roomId, { secret: speakerSecret, joinMeeting: false })
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user