From f0a6d63f4d7b30d6639f75a42bfb472ae967562a Mon Sep 17 00:00:00 2001 From: juancarmore Date: Wed, 14 Jan 2026 13:19:03 +0100 Subject: [PATCH] backend: add currentParticipantIdentity to room member schema and update it based on participant webhooks --- .../mongoose-schemas/room-member.schema.ts | 4 ++ .../src/services/livekit-webhook.service.ts | 44 +++++++++++++++++-- .../src/services/room-member.service.ts | 26 +++++++++++ meet-ce/typings/src/room-member.ts | 1 + 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/meet-ce/backend/src/models/mongoose-schemas/room-member.schema.ts b/meet-ce/backend/src/models/mongoose-schemas/room-member.schema.ts index fffff19b..b867fea5 100644 --- a/meet-ce/backend/src/models/mongoose-schemas/room-member.schema.ts +++ b/meet-ce/backend/src/models/mongoose-schemas/room-member.schema.ts @@ -87,6 +87,10 @@ const MeetRoomMemberSchema = new Schema( customPermissions: { type: MeetRoomMemberPartialPermissionsSchema, required: false + }, + currentParticipantIdentity: { + type: String, + required: false } }, { diff --git a/meet-ce/backend/src/services/livekit-webhook.service.ts b/meet-ce/backend/src/services/livekit-webhook.service.ts index d7f8c512..5ec86cb0 100644 --- a/meet-ce/backend/src/services/livekit-webhook.service.ts +++ b/meet-ce/backend/src/services/livekit-webhook.service.ts @@ -8,6 +8,7 @@ import { MeetLock } from '../helpers/redis.helper.js'; import { MeetRoomHelper } from '../helpers/room.helper.js'; import { DistributedEventType } from '../models/distributed-event.model.js'; import { RecordingRepository } from '../repositories/recording.repository.js'; +import { RoomMemberRepository } from '../repositories/room-member.repository.js'; import { RoomRepository } from '../repositories/room.repository.js'; import { DistributedEventService } from './distributed-event.service.js'; import { FrontendEventService } from './frontend-event.service.js'; @@ -18,7 +19,6 @@ import { OpenViduWebhookService } from './openvidu-webhook.service.js'; import { RecordingService } from './recording.service.js'; import { RoomMemberService } from './room-member.service.js'; import { RoomService } from './room.service.js'; -import { RoomMemberRepository } from '../repositories/room-member.repository.js'; @injectable() export class LivekitWebhookService { @@ -160,7 +160,8 @@ export class LivekitWebhookService { /** * * Handles the 'participant_joined' event by gathering relevant room and participant information, - * checking room status, and sending a data payload with room status information to the newly joined participant. + * updating the room member's currentParticipantIdentity if applicable, + * and sending a room status signal to OpenVidu components. * @param room - Information about the room where the participant joined. * @param participant - Information about the newly joined participant. */ @@ -168,6 +169,23 @@ export class LivekitWebhookService { // Skip if the participant is an egress participant if (this.livekitService.isEgressParticipant(participant)) return; + // Update room member's currentParticipantIdentity if this is an identified member + if (participant.metadata) { + try { + const metadata = JSON.parse(participant.metadata); + + if (metadata.memberId) { + await this.roomMemberService.updateCurrentParticipantIdentity( + room.name, + metadata.memberId, + participant.identity + ); + } + } catch (error) { + this.logger.warn(`Failed to set room member currentParticipantIdentity:`, error); + } + } + try { const { recordings } = await this.recordingService.getAllRecordings({ roomId: room.name }); await this.frontendEventService.sendRoomStatusSignalToOpenViduComponents( @@ -181,8 +199,9 @@ export class LivekitWebhookService { } /** - * Handles the 'participant_left' event by releasing the participant's reserved name - * to make it available for other participants. + * Handles the 'participant_left' event by gathering relevant room and participant information, + * clearing the participant identity from the room member if applicable, + * and releasing any reserved participant names. * @param room - Information about the room where the participant left. * @param participant - Information about the participant who left. */ @@ -190,6 +209,23 @@ export class LivekitWebhookService { // Skip if the participant is an egress participant if (this.livekitService.isEgressParticipant(participant)) return; + // Clear room member's currentParticipantIdentity if this is an identified member + if (participant.metadata) { + try { + const metadata = JSON.parse(participant.metadata); + + if (metadata.memberId) { + await this.roomMemberService.updateCurrentParticipantIdentity( + room.name, + metadata.memberId, + undefined + ); + } + } catch (error) { + this.logger.warn(`Failed to clear room member currentParticipantIdentity:`, error); + } + } + try { // Release the participant's reserved name await this.roomMemberService.releaseParticipantName(room.name, participant.name); diff --git a/meet-ce/backend/src/services/room-member.service.ts b/meet-ce/backend/src/services/room-member.service.ts index 8055053f..2e692208 100644 --- a/meet-ce/backend/src/services/room-member.service.ts +++ b/meet-ce/backend/src/services/room-member.service.ts @@ -191,6 +191,32 @@ export class RoomMemberService { return this.roomMemberRepository.update(member); } + /** + * Updates the currentParticipantIdentity for a room member. + * + * @param roomId - The ID of the room + * @param memberId - The ID of the member + * @param participantIdentity - The participant identity to set (or undefined to clear it) + */ + async updateCurrentParticipantIdentity( + roomId: string, + memberId: string, + participantIdentity: string | undefined + ): Promise { + const member = await this.getRoomMember(roomId, memberId); + + if (!member) { + this.logger.warn( + `Cannot update currentParticipantIdentity: member '${memberId}' not found in room '${roomId}'` + ); + return; + } + + member.currentParticipantIdentity = participantIdentity; + await this.roomMemberRepository.update(member); + this.logger.info(`Updated currentParticipantIdentity for member '${memberId}' in room '${roomId}'`); + } + /** * Deletes a room member. * diff --git a/meet-ce/typings/src/room-member.ts b/meet-ce/typings/src/room-member.ts index 9aca4f6e..6d38667c 100644 --- a/meet-ce/typings/src/room-member.ts +++ b/meet-ce/typings/src/room-member.ts @@ -24,6 +24,7 @@ export interface MeetRoomMember { baseRole: MeetRoomMemberRole; // The base role of the member in the room customPermissions?: Partial; // Custom permissions for the member (if any) effectivePermissions: MeetRoomMemberPermissions; // Effective permissions for the member (base role + custom permissions) + currentParticipantIdentity?: string; // The participant identity if the member is currently in a meeting, undefined otherwise } /**