refactor: replace participantName with participantIdentity for consistency
This commit is contained in:
parent
1071c4c97e
commit
972f6f4f90
@ -31,7 +31,7 @@ export const generateParticipantToken = async (req: Request, res: Response) => {
|
||||
|
||||
try {
|
||||
const claims = tokenService.getClaimsIgnoringExpiration(previousToken);
|
||||
const metadata = JSON.parse(claims.metadata || '{}');
|
||||
const metadata = participantService.parseMetadata(claims.metadata || '{}');
|
||||
currentRoles = metadata.roles;
|
||||
} catch (error) {
|
||||
logger.verbose('Error extracting roles from previous token:', error);
|
||||
@ -80,11 +80,12 @@ export const refreshParticipantToken = async (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
// Extract roles from the previous token
|
||||
const participantService = container.get(ParticipantService);
|
||||
let currentRoles: { role: ParticipantRole; permissions: OpenViduMeetPermissions }[] = [];
|
||||
|
||||
try {
|
||||
const claims = tokenService.getClaimsIgnoringExpiration(previousToken);
|
||||
const metadata = JSON.parse(claims.metadata || '{}');
|
||||
const metadata = participantService.parseMetadata(claims.metadata || '{}');
|
||||
currentRoles = metadata.roles;
|
||||
} catch (err) {
|
||||
logger.verbose('Error extracting roles from previous token:', err);
|
||||
@ -94,7 +95,6 @@ export const refreshParticipantToken = async (req: Request, res: Response) => {
|
||||
|
||||
const participantOptions: ParticipantOptions = req.body;
|
||||
const { roomId } = participantOptions;
|
||||
const participantService = container.get(ParticipantService);
|
||||
|
||||
try {
|
||||
logger.verbose(`Refreshing participant token for room '${roomId}'`);
|
||||
@ -111,11 +111,26 @@ export const refreshParticipantToken = async (req: Request, res: Response) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const updateParticipant = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const participantService = container.get(ParticipantService);
|
||||
const { roomId, participantIdentity } = req.params;
|
||||
const { role } = req.body;
|
||||
|
||||
try {
|
||||
logger.verbose(`Changing role of participant '${participantIdentity}' in room '${roomId}' to '${role}'`);
|
||||
await participantService.updateParticipantRole(roomId, participantIdentity, role);
|
||||
res.status(200).json({ message: `Participant '${participantIdentity}' role updated to '${role}'` });
|
||||
} catch (error) {
|
||||
handleError(res, error, `changing role for participant '${participantIdentity}' in room '${roomId}'`);
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteParticipant = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const roomService = container.get(RoomService);
|
||||
const participantService = container.get(ParticipantService);
|
||||
const { roomId, participantName } = req.params;
|
||||
const { roomId, participantIdentity } = req.params;
|
||||
|
||||
// Check if the room exists
|
||||
try {
|
||||
@ -125,25 +140,10 @@ export const deleteParticipant = async (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
try {
|
||||
logger.verbose(`Deleting participant '${participantName}' from room '${roomId}'`);
|
||||
await participantService.deleteParticipant(roomId, participantName);
|
||||
logger.verbose(`Deleting participant '${participantIdentity}' from room '${roomId}'`);
|
||||
await participantService.deleteParticipant(roomId, participantIdentity);
|
||||
res.status(200).json({ message: 'Participant deleted' });
|
||||
} catch (error) {
|
||||
handleError(res, error, `deleting participant '${participantName}' from room '${roomId}'`);
|
||||
}
|
||||
};
|
||||
|
||||
export const updateParticipant = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const participantService = container.get(ParticipantService);
|
||||
const { roomId, participantName } = req.params;
|
||||
const { role } = req.body;
|
||||
|
||||
try {
|
||||
logger.verbose(`Changing role of participant '${participantName}' in room '${roomId}' to '${role}'`);
|
||||
await participantService.updateParticipantRole(roomId, participantName, role);
|
||||
res.status(200).json({ message: `Participant '${participantName}' role updated to ${role}` });
|
||||
} catch (error) {
|
||||
handleError(res, error, `changing role for participant '${participantName}' in room '${roomId}'`);
|
||||
handleError(res, error, `deleting participant '${participantIdentity}' from room '${roomId}'`);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2,7 +2,13 @@ import bodyParser from 'body-parser';
|
||||
import { Router } from 'express';
|
||||
import * as meetingCtrl from '../controllers/meeting.controller.js';
|
||||
import * as participantCtrl from '../controllers/participant.controller.js';
|
||||
import { participantTokenValidator, withAuth, withModeratorPermissions, withValidParticipantRole, withValidRoomId } from '../middlewares/index.js';
|
||||
import {
|
||||
participantTokenValidator,
|
||||
validateUpdateParticipantRequest,
|
||||
withAuth,
|
||||
withModeratorPermissions,
|
||||
withValidRoomId
|
||||
} from '../middlewares/index.js';
|
||||
|
||||
export const internalMeetingRouter = Router();
|
||||
internalMeetingRouter.use(bodyParser.urlencoded({ extended: true }));
|
||||
@ -12,23 +18,22 @@ internalMeetingRouter.use(bodyParser.json());
|
||||
internalMeetingRouter.delete(
|
||||
'/:roomId',
|
||||
withAuth(participantTokenValidator),
|
||||
withModeratorPermissions,
|
||||
withValidRoomId,
|
||||
withModeratorPermissions,
|
||||
meetingCtrl.endMeeting
|
||||
);
|
||||
internalMeetingRouter.delete(
|
||||
'/:roomId/participants/:participantName',
|
||||
withAuth(participantTokenValidator),
|
||||
withModeratorPermissions,
|
||||
withValidRoomId,
|
||||
participantCtrl.deleteParticipant
|
||||
);
|
||||
|
||||
internalMeetingRouter.patch(
|
||||
'/:roomId/participants/:participantName',
|
||||
'/:roomId/participants/:participantIdentity',
|
||||
withAuth(participantTokenValidator),
|
||||
withModeratorPermissions,
|
||||
withValidRoomId,
|
||||
withValidParticipantRole,
|
||||
withModeratorPermissions,
|
||||
validateUpdateParticipantRequest,
|
||||
participantCtrl.updateParticipant
|
||||
);
|
||||
internalMeetingRouter.delete(
|
||||
'/:roomId/participants/:participantIdentity',
|
||||
withAuth(participantTokenValidator),
|
||||
withValidRoomId,
|
||||
withModeratorPermissions,
|
||||
participantCtrl.deleteParticipant
|
||||
);
|
||||
|
||||
@ -23,8 +23,8 @@ import {
|
||||
internalError,
|
||||
OpenViduMeetError
|
||||
} from '../models/error.model.js';
|
||||
import { LoggerService } from './index.js';
|
||||
import { chunkArray } from '../utils/array.utils.js';
|
||||
import { LoggerService } from './index.js';
|
||||
|
||||
@injectable()
|
||||
export class LiveKitService {
|
||||
@ -77,7 +77,7 @@ export class LiveKitService {
|
||||
*/
|
||||
async roomHasParticipants(roomName: string): Promise<boolean> {
|
||||
try {
|
||||
const participants = await this.roomClient.listParticipants(roomName);
|
||||
const participants = await this.listRoomParticipants(roomName);
|
||||
return participants.length > 0;
|
||||
} catch (error) {
|
||||
return false;
|
||||
@ -167,20 +167,35 @@ export class LiveKitService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all participants in a LiveKit room.
|
||||
*
|
||||
* @param roomName - The name of the room to list participants from
|
||||
* @returns A promise that resolves to an array of participant information
|
||||
*/
|
||||
async listRoomParticipants(roomName: string): Promise<ParticipantInfo[]> {
|
||||
try {
|
||||
return await this.roomClient.listParticipants(roomName);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error listing participants for room '${roomName}': ${error}`);
|
||||
throw internalError(`listing participants for room '${roomName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about a specific participant in a LiveKit room.
|
||||
*
|
||||
* @param roomName - The name of the room where the participant is located
|
||||
* @param participantName - The name of the participant to retrieve
|
||||
* @param participantIdentity - The identity of the participant to retrieve
|
||||
* @returns A Promise that resolves to the participant's information
|
||||
* @throws An internal error if the participant cannot be found or another error occurs
|
||||
*/
|
||||
async getParticipant(roomName: string, participantName: string): Promise<ParticipantInfo> {
|
||||
async getParticipant(roomName: string, participantIdentity: string): Promise<ParticipantInfo> {
|
||||
try {
|
||||
return await this.roomClient.getParticipant(roomName, participantName);
|
||||
return await this.roomClient.getParticipant(roomName, participantIdentity);
|
||||
} catch (error) {
|
||||
this.logger.warn(`Participant ${participantName} not found in room ${roomName}: ${error}`);
|
||||
throw errorParticipantNotFound(participantName, roomName);
|
||||
this.logger.warn(`Participant ${participantIdentity} not found in room ${roomName}: ${error}`);
|
||||
throw errorParticipantNotFound(participantIdentity, roomName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,31 +203,31 @@ export class LiveKitService {
|
||||
* Updates the metadata of a participant in a LiveKit room.
|
||||
*
|
||||
* @param roomName - The name of the room where the participant is located
|
||||
* @param participantName - The name of the participant whose metadata will be updated
|
||||
* @param participantIdentity - The identity of the participant whose metadata will be updated
|
||||
* @param metadata - The new metadata to set for the participant
|
||||
* @returns A Promise that resolves when the metadata has been successfully updated
|
||||
* @throws An internal error if there is an issue updating the metadata
|
||||
*/
|
||||
async updateParticipantMetadata(roomName: string, participantName: string, metadata: string): Promise<void> {
|
||||
async updateParticipantMetadata(roomName: string, participantIdentity: string, metadata: string): Promise<void> {
|
||||
try {
|
||||
await this.roomClient.updateParticipant(roomName, participantName, metadata);
|
||||
this.logger.verbose(`Updated metadata for participant ${participantName} in room ${roomName}`);
|
||||
await this.roomClient.updateParticipant(roomName, participantIdentity, metadata);
|
||||
this.logger.verbose(`Updated metadata for participant '${participantIdentity}' in room '${roomName}'`);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Error updating metadata for participant ${participantName} in room ${roomName}: ${error}`
|
||||
`Error updating metadata for participant '${participantIdentity}' in room '${roomName}': ${error}`
|
||||
);
|
||||
throw internalError(`updating metadata for participant '${participantName}' in room '${roomName}'`);
|
||||
throw internalError(`updating metadata for participant '${participantIdentity}' in room '${roomName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
async deleteParticipant(participantName: string, roomName: string): Promise<void> {
|
||||
const participantExists = await this.participantExists(roomName, participantName);
|
||||
async deleteParticipant(roomName: string, participantIdentity: string): Promise<void> {
|
||||
const participantExists = await this.participantExists(roomName, participantIdentity);
|
||||
|
||||
if (!participantExists) {
|
||||
throw errorParticipantNotFound(participantName, roomName);
|
||||
throw errorParticipantNotFound(participantIdentity, roomName);
|
||||
}
|
||||
|
||||
await this.roomClient.removeParticipant(roomName, participantName);
|
||||
await this.roomClient.removeParticipant(roomName, participantIdentity);
|
||||
}
|
||||
|
||||
async sendData(roomName: string, rawData: Record<string, any>, options: SendDataOptions): Promise<void> {
|
||||
@ -369,10 +384,10 @@ export class LiveKitService {
|
||||
return participant.identity.startsWith('EG_') && participant.permission?.recorder === true;
|
||||
}
|
||||
|
||||
private async participantExists(roomName: string, participantName: string): Promise<boolean> {
|
||||
private async participantExists(roomName: string, participantIdentity: string): Promise<boolean> {
|
||||
try {
|
||||
const participants: ParticipantInfo[] = await this.roomClient.listParticipants(roomName);
|
||||
return participants.some((participant) => participant.identity === participantName);
|
||||
const participants: ParticipantInfo[] = await this.listRoomParticipants(roomName);
|
||||
return participants.some((participant) => participant.identity === participantIdentity);
|
||||
} catch (error: any) {
|
||||
this.logger.error(error);
|
||||
|
||||
|
||||
@ -7,9 +7,10 @@ import {
|
||||
} from '@typings-ce';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ParticipantInfo } from 'livekit-server-sdk';
|
||||
import { MeetRoomHelper } from '../helpers/room.helper.js';
|
||||
import { validateMeetTokenMetadata } from '../middlewares/index.js';
|
||||
import { errorParticipantAlreadyExists, errorParticipantNotFound } from '../models/error.model.js';
|
||||
import { FrontendEventService, LiveKitService, LoggerService, RoomService, TokenService } from './index.js';
|
||||
import { MeetRoomHelper } from '../helpers/room.helper.js';
|
||||
|
||||
@injectable()
|
||||
export class ParticipantService {
|
||||
@ -64,26 +65,26 @@ export class ParticipantService {
|
||||
return this.tokenService.generateParticipantToken(participantOptions, permissions.livekit, currentRoles, role);
|
||||
}
|
||||
|
||||
async getParticipant(roomId: string, participantName: string): Promise<ParticipantInfo | null> {
|
||||
this.logger.verbose(`Fetching participant '${participantName}'`);
|
||||
return this.livekitService.getParticipant(roomId, participantName);
|
||||
async getParticipant(roomId: string, participantIdentity: string): Promise<ParticipantInfo> {
|
||||
this.logger.verbose(`Fetching participant '${participantIdentity}'`);
|
||||
return this.livekitService.getParticipant(roomId, participantIdentity);
|
||||
}
|
||||
|
||||
async participantExists(roomId: string, participantName: string): Promise<boolean> {
|
||||
this.logger.verbose(`Checking if participant '${participantName}' exists in room '${roomId}'`);
|
||||
async participantExists(roomId: string, participantIdentity: string): Promise<boolean> {
|
||||
this.logger.verbose(`Checking if participant '${participantIdentity}' exists in room '${roomId}'`);
|
||||
|
||||
try {
|
||||
const participant = await this.getParticipant(roomId, participantName);
|
||||
return participant !== null;
|
||||
await this.getParticipant(roomId, participantIdentity);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteParticipant(roomId: string, participantName: string): Promise<void> {
|
||||
this.logger.verbose(`Deleting participant '${participantName}' from room '${roomId}'`);
|
||||
async deleteParticipant(roomId: string, participantIdentity: string): Promise<void> {
|
||||
this.logger.verbose(`Deleting participant '${participantIdentity}' from room '${roomId}'`);
|
||||
|
||||
return this.livekitService.deleteParticipant(participantName, roomId);
|
||||
return this.livekitService.deleteParticipant(roomId, participantIdentity);
|
||||
}
|
||||
|
||||
getParticipantPermissions(roomId: string, role: ParticipantRole, addJoinPermission = true): ParticipantPermissions {
|
||||
@ -97,36 +98,42 @@ export class ParticipantService {
|
||||
}
|
||||
}
|
||||
|
||||
async updateParticipantRole(roomId: string, participantName: string, newRole: ParticipantRole): Promise<void> {
|
||||
async updateParticipantRole(roomId: string, participantIdentity: string, newRole: ParticipantRole): Promise<void> {
|
||||
try {
|
||||
const meetRoom = await this.roomService.getMeetRoom(roomId);
|
||||
|
||||
const participant = await this.getParticipant(roomId, participantName);
|
||||
const participant = await this.getParticipant(roomId, participantIdentity);
|
||||
const metadata: MeetTokenMetadata = this.parseMetadata(participant.metadata);
|
||||
|
||||
const metadata: MeetTokenMetadata = this.parseMetadata(participant!.metadata);
|
||||
// Update selected role and roles array
|
||||
metadata.selectedRole = newRole;
|
||||
const currentRoles = metadata.roles;
|
||||
|
||||
if (!metadata || typeof metadata !== 'object') {
|
||||
throw new Error(`Invalid metadata for participant ${participantName}`);
|
||||
if (!currentRoles.some((r) => r.role === newRole)) {
|
||||
const { openvidu } = this.getParticipantPermissions(roomId, newRole);
|
||||
currentRoles.push({ role: newRole, permissions: openvidu });
|
||||
}
|
||||
|
||||
// TODO: Should we update the roles array as well?
|
||||
metadata.selectedRole = newRole;
|
||||
|
||||
await this.livekitService.updateParticipantMetadata(roomId, participantName, JSON.stringify(metadata));
|
||||
await this.livekitService.updateParticipantMetadata(roomId, participantIdentity, JSON.stringify(metadata));
|
||||
|
||||
const { speakerSecret, moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(meetRoom);
|
||||
|
||||
const secret = newRole === ParticipantRole.MODERATOR ? moderatorSecret : speakerSecret;
|
||||
await this.frontendEventService.sendParticipantRoleUpdatedSignal(roomId, participantName, newRole, secret);
|
||||
await this.frontendEventService.sendParticipantRoleUpdatedSignal(
|
||||
roomId,
|
||||
participantIdentity,
|
||||
newRole,
|
||||
secret
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error('Error changing participant role:', error);
|
||||
this.logger.error('Error updating participant role:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
protected parseMetadata(metadata: string): MeetTokenMetadata {
|
||||
parseMetadata(metadata: string): MeetTokenMetadata {
|
||||
try {
|
||||
return JSON.parse(metadata);
|
||||
const parsedMetadata = JSON.parse(metadata);
|
||||
return validateMeetTokenMetadata(parsedMetadata);
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to parse participant metadata:', error);
|
||||
throw new Error('Invalid participant metadata format');
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { RoomData, setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||
|
||||
const participantName = 'TEST_PARTICIPANT';
|
||||
const participantIdentity = 'TEST_PARTICIPANT';
|
||||
|
||||
describe('Meetings API Tests', () => {
|
||||
let livekitService: LiveKitService;
|
||||
@ -34,17 +34,17 @@ describe('Meetings API Tests', () => {
|
||||
|
||||
it('should remove participant from LiveKit room', async () => {
|
||||
// Check if participant exists before deletion
|
||||
const participant = await livekitService.getParticipant(roomData.room.roomId, participantName);
|
||||
const participant = await livekitService.getParticipant(roomData.room.roomId, participantIdentity);
|
||||
expect(participant).toBeDefined();
|
||||
expect(participant.identity).toBe(participantName);
|
||||
expect(participant.identity).toBe(participantIdentity);
|
||||
|
||||
// Delete the participant
|
||||
const response = await deleteParticipant(roomData.room.roomId, participantName, roomData.moderatorCookie);
|
||||
const response = await deleteParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorCookie);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Check if the participant has been removed from LiveKit
|
||||
try {
|
||||
await livekitService.getParticipant(roomData.room.roomId, participantName);
|
||||
await livekitService.getParticipant(roomData.room.roomId, participantIdentity);
|
||||
} catch (error) {
|
||||
expect((error as OpenViduMeetError).statusCode).toBe(404);
|
||||
}
|
||||
@ -65,7 +65,7 @@ describe('Meetings API Tests', () => {
|
||||
let response = await deleteRoom(roomData.room.roomId, { force: true });
|
||||
expect(response.status).toBe(204);
|
||||
|
||||
response = await deleteParticipant(roomData.room.roomId, participantName, roomData.moderatorCookie);
|
||||
response = await deleteParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorCookie);
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body.error).toBe('Room Error');
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user