diff --git a/backend/src/services/livekit-webhook.service.ts b/backend/src/services/livekit-webhook.service.ts index 92aa7ed..5b665ea 100644 --- a/backend/src/services/livekit-webhook.service.ts +++ b/backend/src/services/livekit-webhook.service.ts @@ -217,13 +217,12 @@ export class LivekitWebhookService { try { const recordingInfo: MeetRecordingInfo = RecordingHelper.toRecordingInfo(egressInfo); const { roomId, recordingId, status } = recordingInfo; - const metadataPath = RecordingHelper.buildMetadataFilePath(recordingId); this.logger.debug(`Recording '${recordingId}' in room '${roomId}' status: '${status}'`); // Common tasks for all webhook types const commonTasks = [ - this.s3Service.saveObject(metadataPath, recordingInfo), + this.storageService.saveRecordingMetadata(recordingInfo), this.recordingService.sendRecordingSignalToOpenViduComponents(roomId, recordingInfo) ]; diff --git a/backend/src/services/recording.service.ts b/backend/src/services/recording.service.ts index bb12609..9a3718e 100644 --- a/backend/src/services/recording.service.ts +++ b/backend/src/services/recording.service.ts @@ -28,6 +28,7 @@ import { IScheduledTask, LiveKitService, LoggerService, + MeetStorageService, MutexService, RedisLock, RoomService, @@ -45,6 +46,7 @@ export class RecordingService { @inject(MutexService) protected mutexService: MutexService, @inject(TaskSchedulerService) protected taskSchedulerService: TaskSchedulerService, @inject(SystemEventService) protected systemEventService: SystemEventService, + @inject(MeetStorageService) protected storageService: MeetStorageService, @inject(LoggerService) protected logger: LoggerService ) { // Register the recording garbage collector task @@ -544,7 +546,7 @@ export class RecordingService { protected generateCompositeOptionsFromRequest(layout = 'grid'): RoomCompositeOptions { return { - layout: layout, + layout: layout // customBaseUrl: customLayout, // audioOnly: false, // videoOnly: false @@ -645,10 +647,9 @@ export class RecordingService { } protected async updateRecordingStatus(recordingId: string, status: MeetRecordingStatus): Promise { - const metadataPath = RecordingHelper.buildMetadataFilePath(recordingId); const recordingInfo = await this.getRecording(recordingId); recordingInfo.status = status; - await this.s3Service.saveObject(metadataPath, recordingInfo); + await this.storageService.saveRecordingMetadata(recordingInfo); } /** diff --git a/backend/src/services/storage/providers/s3-storage.provider.ts b/backend/src/services/storage/providers/s3-storage.provider.ts index 4a961c1..073de6d 100644 --- a/backend/src/services/storage/providers/s3-storage.provider.ts +++ b/backend/src/services/storage/providers/s3-storage.provider.ts @@ -4,6 +4,7 @@ import { inject, injectable } from 'inversify'; import INTERNAL_CONFIG from '../../../config/internal-config.js'; import { OpenViduMeetError, RedisKeyName } from '../../../models/index.js'; import { LoggerService, RedisService, S3Service, StorageProvider } from '../../index.js'; +import { RecordingHelper } from '../../../helpers/recording.helper.js'; /** * Implementation of the StorageProvider interface using AWS S3 for persistent storage @@ -360,9 +361,14 @@ export class S3StorageProvider< } async saveRecordingMetadata(recordingInfo: MRec): Promise { - //TODO : Implement this method to save recording metadata for a room - this.logger.warn('saveMeetRecordingInfo is not implemented yet'); - return recordingInfo; + try { + const metadataPath = RecordingHelper.buildMetadataFilePath(recordingInfo.recordingId); + await this.s3Service.saveObject(metadataPath, recordingInfo); + return recordingInfo; + } catch (error) { + this.handleError(error, `Error saving recording metadata for recording ${recordingInfo.recordingId}`); + throw error; + } } async deleteRecordingMetadata(recordingId: string): Promise { diff --git a/backend/src/services/storage/storage.service.ts b/backend/src/services/storage/storage.service.ts index 6cdf40a..db69f06 100644 --- a/backend/src/services/storage/storage.service.ts +++ b/backend/src/services/storage/storage.service.ts @@ -1,4 +1,4 @@ -import { AuthMode, AuthType, GlobalPreferences, MeetRoom } from '@typings-ce'; +import { AuthMode, AuthType, GlobalPreferences, MeetRecordingInfo, MeetRoom } from '@typings-ce'; import { inject, injectable } from 'inversify'; import ms from 'ms'; import { MEET_NAME_ID, MEET_SECRET, MEET_USER, MEET_WEBHOOK_ENABLED, MEET_WEBHOOK_URL } from '../../environment.js'; @@ -18,7 +18,8 @@ import { LoggerService, MutexService, StorageFactory, StorageProvider } from '.. @injectable() export class MeetStorageService< GPrefs extends GlobalPreferences = GlobalPreferences, - MRoom extends MeetRoom = MeetRoom + MRoom extends MeetRoom = MeetRoom, + MRec extends MeetRecordingInfo = MeetRecordingInfo > { protected storageProvider: StorageProvider; constructor( @@ -181,6 +182,16 @@ export class MeetStorageService< return this.storageProvider.updateArchivedRoomMetadata(roomId); } + /** + * Saves recording metadata to the storage provider. + * + * @param recordingInfo - The recording metadata object to be saved + * @returns A promise that resolves to the saved recording metadata object + */ + async saveRecordingMetadata(recordingInfo: MRec): Promise { + return this.storageProvider.saveRecordingMetadata(recordingInfo) as Promise; + } + /** * Returns the default global preferences. * @returns {GPrefs}