backend: refactor RecordingService to use StorageProvider for listing objects and remove S3Service dependency

This commit is contained in:
Carlos Santos 2025-05-30 11:06:48 +02:00
parent 2872383b01
commit 333c7da5b2
5 changed files with 86 additions and 16 deletions

View File

@ -32,7 +32,6 @@ import {
MutexService,
RedisLock,
RoomService,
S3Service,
SystemEventService,
TaskSchedulerService
} from './index.js';
@ -40,7 +39,6 @@ import {
@injectable()
export class RecordingService {
constructor(
@inject(S3Service) protected s3Service: S3Service,
@inject(LiveKitService) protected livekitService: LiveKitService,
@inject(RoomService) protected roomService: RoomService,
@inject(MutexService) protected mutexService: MutexService,
@ -306,7 +304,7 @@ export class RecordingService {
protected async shouldDeleteRoomMetadata(roomId: string): Promise<boolean | null> {
try {
const metadataPrefix = `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/.metadata/${roomId}`;
const { Contents } = await this.s3Service.listObjectsPaginated(metadataPrefix);
const { Contents } = await this.storageService.listObjects(metadataPrefix, 1);
// If no metadata files exist or the list is empty, the room metadata should be deleted
return !Contents || Contents.length === 0;
@ -346,10 +344,11 @@ export class RecordingService {
try {
// Construct the room prefix if a room ID is provided
const roomPrefix = roomId ? `/${roomId}` : '';
const recordingPrefix = `${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/.metadata${roomPrefix}`;
// Retrieve the recordings from the S3 bucket
const { Contents, IsTruncated, NextContinuationToken } = await this.s3Service.listObjectsPaginated(
`${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/.metadata${roomPrefix}`,
const { Contents, IsTruncated, NextContinuationToken } = await this.storageService.listObjects(
recordingPrefix,
maxItems,
nextPageToken
);

View File

@ -128,7 +128,6 @@ export class S3Service {
additionalPrefix = '',
maxKeys = 50,
continuationToken?: string,
searchPattern = '',
bucket: string = MEET_S3_BUCKET
): Promise<ListObjectsV2CommandOutput> {
// The complete prefix is constructed by combining the subbucket and the additionalPrefix.
@ -145,16 +144,7 @@ export class S3Service {
});
try {
const response: ListObjectsV2CommandOutput = await this.s3.send(command);
// If searchPattern is provided, filter the results.
if (searchPattern) {
const regex = new RegExp(searchPattern);
response.Contents = (response.Contents || []).filter((item) => item.Key && regex.test(item.Key));
}
return response;
return await this.s3.send(command);
} catch (error: any) {
this.logger.error(`S3 listObjectsPaginated: error listing objects with prefix "${basePrefix}": ${error}`);
throw internalError('listing objects from S3');

View File

@ -58,6 +58,39 @@ export class S3StorageProvider<
}
}
/**
* Lists objects in the storage with optional pagination support.
*
* @param prefix - The prefix to filter objects by (acts as a folder path)
* @param maxItems - Maximum number of items to return (optional)
* @param nextPageToken - Token for pagination to get the next page (optional)
* @returns Promise resolving to paginated list of objects with metadata
*/
async listObjects(
prefix: string,
maxItems?: number,
nextPageToken?: string
): Promise<{
Contents?: Array<{
Key?: string;
LastModified?: Date;
Size?: number;
ETag?: string;
}>;
IsTruncated?: boolean;
NextContinuationToken?: string;
}> {
try {
this.logger.debug(
`Listing objects with prefix: ${prefix}, maxItems: ${maxItems}, nextPageToken: ${nextPageToken}`
);
return await this.s3Service.listObjectsPaginated(prefix, maxItems, nextPageToken);
} catch (error) {
this.handleError(error, `Error listing objects with prefix ${prefix}`);
throw error;
}
}
/**
* Initializes global preferences. If no preferences exist, persists the provided defaults.
* If preferences exist but belong to a different project, they are replaced.

View File

@ -33,6 +33,29 @@ export interface StorageProvider<
*/
getObjectHeaders(filePath: string): Promise<{ contentLength?: number; contentType?: string }>;
/**
* Lists objects in the storage with optional pagination support.
*
* @param prefix - The prefix to filter objects by (acts as a folder path)
* @param maxItems - Maximum number of items to return (optional)
* @param nextPageToken - Token for pagination to get the next page (optional)
* @returns Promise resolving to paginated list of objects with metadata
*/
listObjects(
prefix: string,
maxItems?: number,
nextPageToken?: string
): Promise<{
Contents?: Array<{
Key?: string;
LastModified?: Date;
Size?: number;
ETag?: string;
}>;
IsTruncated?: boolean;
NextContinuationToken?: string;
}>;
/**
* Retrieves the global preferences of Openvidu Meet.
*

View File

@ -42,6 +42,31 @@ export class MeetStorageService<
}
}
/**
* Lists objects in the storage with optional pagination support.
*
* @param prefix - The prefix to filter objects by (acts as a folder path)
* @param maxItems - Maximum number of items to return (optional)
* @param nextPageToken - Token for pagination to get the next page (optional)
* @returns Promise resolving to paginated list of objects with metadata
*/
listObjects(
prefix: string,
maxItems?: number,
nextPageToken?: string
): Promise<{
Contents?: Array<{
Key?: string;
LastModified?: Date;
Size?: number;
ETag?: string;
}>;
IsTruncated?: boolean;
NextContinuationToken?: string;
}> {
return this.storageProvider.listObjects(prefix, maxItems, nextPageToken);
}
/**
* Initializes default preferences if not already initialized.
* @returns {Promise<GPrefs>} Default global preferences.