backend: Saved recording preferences into the room_metadata json file

This commit is contained in:
Carlos Santos 2025-04-22 12:56:22 +02:00
parent 47350f1b10
commit c33ee7218b
2 changed files with 42 additions and 29 deletions

View File

@ -199,7 +199,10 @@ export class LivekitWebhookService {
// Send webhook notification // Send webhook notification
switch (webhookAction) { switch (webhookAction) {
case 'started': case 'started':
tasks.push(this.openViduWebhookService.sendRecordingStartedWebhook(recordingInfo)); tasks.push(
this.saveRoomMetadataFileIfNeeded(roomId),
this.openViduWebhookService.sendRecordingStartedWebhook(recordingInfo)
);
break; break;
case 'updated': case 'updated':
tasks.push(this.openViduWebhookService.sendRecordingUpdatedWebhook(recordingInfo)); tasks.push(this.openViduWebhookService.sendRecordingUpdatedWebhook(recordingInfo));
@ -217,7 +220,6 @@ export class LivekitWebhookService {
break; break;
case 'ended': case 'ended':
tasks.push( tasks.push(
this.saveRoomSecretsFileIfNeeded(roomId),
this.openViduWebhookService.sendRecordingEndedWebhook(recordingInfo), this.openViduWebhookService.sendRecordingEndedWebhook(recordingInfo),
this.recordingService.releaseRoomRecordingActiveLock(roomId) this.recordingService.releaseRoomRecordingActiveLock(roomId)
); );
@ -235,20 +237,22 @@ export class LivekitWebhookService {
} }
/** /**
* Saves room secrets to an S3 bucket if they haven't been saved already. * Saves room metadata to a JSON file in the S3 bucket if it doesn't already exist.
* *
* This method checks if secrets for the specified room exist in the S3 storage. * This method checks if the metadata file for the given room already exists in the
* If they don't exist, it retrieves the room information, extracts the publisher * S3 bucket. If not, it retrieves the room information, extracts the necessary
* and moderator secrets, and saves them to an S3 bucket under the path * secrets and preferences, and saves them to a metadata JSON file in the
* `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/.metadata/${roomId}/secrets.json`. * .metadata/{roomId}/ directory of the S3 bucket.
*
* @param roomId - The unique identifier of the room
*/ */
protected async saveRoomSecretsFileIfNeeded(roomId: string): Promise<void> { protected async saveRoomMetadataFileIfNeeded(roomId: string): Promise<void> {
try { try {
const filePath = `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/.metadata/${roomId}/secrets.json`; const filePath = `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/.metadata/${roomId}/room_metadata.json`;
const fileExists = await this.s3Service.exists(filePath); const fileExists = await this.s3Service.exists(filePath);
if (fileExists) { if (fileExists) {
this.logger.debug(`Room secrets already saved for room ${roomId}`); this.logger.debug(`Room metadata already saved for room ${roomId} in recordings bucket`);
return; return;
} }
@ -256,15 +260,18 @@ export class LivekitWebhookService {
if (room) { if (room) {
const { publisherSecret, moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room); const { publisherSecret, moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
const secrets = { const roomMetadata = {
publisherSecret, publisherSecret,
moderatorSecret moderatorSecret,
preferences: {
recordingPreferences: room.preferences?.recordingPreferences
}
}; };
await this.s3Service.saveObject(filePath, secrets); await this.s3Service.saveObject(filePath, roomMetadata);
this.logger.debug(`Room secrets saved for room ${roomId}`); this.logger.debug(`Room metadata saved for room ${roomId} in recordings bucket`);
} }
} catch (error) { } catch (error) {
this.logger.error(`Error saving room secrets for room ${roomId}: ${error}`); this.logger.error(`Error saving room metadata for room ${roomId} in recordings bucket: ${error}`);
} }
} }
} }

View File

@ -401,15 +401,15 @@ export class RecordingService {
const recordingPath = `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/${RecordingHelper.extractFilename(recordingInfo)}`; const recordingPath = `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/${RecordingHelper.extractFilename(recordingInfo)}`;
newFilesToDelete.add(recordingPath); newFilesToDelete.add(recordingPath);
// Get secrets.json file path if it is the only file remaining in the room's metadata directory // Get room_metadata.json file path under recordings bucket if it is the only file remaining in the room's metadata directory
const secretsFilePath = await this.getSecretsFilePathIfOnlyRemaining( const roomMetadataFilePath = await this.getRoomMetadataFilePathIfOnlyRemaining(
recordingInfo.roomId, recordingInfo.roomId,
metadataFilePath, metadataFilePath,
Array.from(new Set([...filesAlreadyAddedForDeletion, ...newFilesToDelete])) Array.from(new Set([...filesAlreadyAddedForDeletion, ...newFilesToDelete]))
); );
if (secretsFilePath) { if (roomMetadataFilePath) {
newFilesToDelete.add(secretsFilePath); newFilesToDelete.add(roomMetadataFilePath);
} }
return { filesToDelete: newFilesToDelete, recordingInfo }; return { filesToDelete: newFilesToDelete, recordingInfo };
@ -537,15 +537,21 @@ export class RecordingService {
} }
/** /**
* Determines if the secrets.json file should be deleted by checking if it would be * Determines if the room_metadata.json file would be the only file remaining in a room's metadata
* the only file remaining in the room's metadata directory after deletion. * directory after specified files are deleted.
* *
* @param roomId - Room identifier * This method examines the contents of a room's metadata directory in S3 storage and checks whether,
* @param metadataFilePath - Path of the metadata file being deleted (for single deletion) * after the deletion of specified files, only the room_metadata.json file would remain. The method
* @param filesToDeleteArray - Array of all files being deleted (for bulk deletion) * handles both single file deletion and bulk deletion scenarios.
* @returns Path of the secrets.json file if it should be deleted, or null otherwise *
* @param roomId - The identifier of the room whose metadata directory is being checked
* @param metadataFilePath - The full path of the metadata file being considered for deletion
* @param filesToDeleteArray - Optional array of file paths that are planned for deletion
*
* @returns The path to the room_metadata.json file if it would be the only remaining file after deletion,
* or null if multiple files would remain or if an error occurs during the process
*/ */
protected async getSecretsFilePathIfOnlyRemaining( protected async getRoomMetadataFilePathIfOnlyRemaining(
roomId: string, roomId: string,
metadataFilePath: string, metadataFilePath: string,
filesToDeleteArray: string[] = [] filesToDeleteArray: string[] = []
@ -568,7 +574,7 @@ export class RecordingService {
).map((item) => item.Key!); ).map((item) => item.Key!);
// If only secrets.json remains, return its path // If only secrets.json remains, return its path
if (remainingFiles.length === 1 && remainingFiles[0].endsWith('secrets.json')) { if (remainingFiles.length === 1 && remainingFiles[0].endsWith('room_metadata.json')) {
return remainingFiles[0]; return remainingFiles[0];
} }
} else { } else {
@ -584,8 +590,8 @@ export class RecordingService {
const otherFiles = Contents.filter((item) => !item.Key?.endsWith(metadataBaseName || '')); const otherFiles = Contents.filter((item) => !item.Key?.endsWith(metadataBaseName || ''));
// If the only other file is secrets.json, return its path // If the only other file is secrets.json, return its path
if (otherFiles.length === 1 && otherFiles[0].Key?.endsWith('secrets.json')) { if (otherFiles.length === 1 && otherFiles[0].Key?.endsWith('room_metadata.json')) {
return `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/.metadata/${roomId}/secrets.json`; return `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/.metadata/${roomId}/room_metadata.json`;
} }
} }