backend: Refactor storage services and remove global preferences service references
This commit is contained in:
parent
9e3644ab06
commit
12ef04964c
@ -1,8 +1,8 @@
|
||||
import { Container } from 'inversify';
|
||||
import {
|
||||
AuthService,
|
||||
GlobalPreferencesService,
|
||||
GlobalPreferencesStorageFactory,
|
||||
MeetStorageService,
|
||||
StorageFactory,
|
||||
LiveKitService,
|
||||
LivekitWebhookService,
|
||||
LoggerService,
|
||||
@ -12,7 +12,7 @@ import {
|
||||
RecordingService,
|
||||
RedisService,
|
||||
RoomService,
|
||||
S3PreferenceStorage,
|
||||
S3Storage,
|
||||
S3Service,
|
||||
SystemEventService,
|
||||
TaskSchedulerService,
|
||||
@ -47,11 +47,11 @@ const registerDependencies = () => {
|
||||
container.bind(RecordingService).toSelf().inSingletonScope();
|
||||
|
||||
container.bind(LivekitWebhookService).toSelf().inSingletonScope();
|
||||
container.bind(GlobalPreferencesService).toSelf().inSingletonScope();
|
||||
container.bind(MeetStorageService).toSelf().inSingletonScope();
|
||||
container.bind(ParticipantService).toSelf().inSingletonScope();
|
||||
|
||||
container.bind(S3PreferenceStorage).toSelf().inSingletonScope();
|
||||
container.bind(GlobalPreferencesStorageFactory).toSelf().inSingletonScope();
|
||||
container.bind(S3Storage).toSelf().inSingletonScope();
|
||||
container.bind(StorageFactory).toSelf().inSingletonScope();
|
||||
|
||||
initializeEagerServices();
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { container } from '../../config/dependency-injector.config.js';
|
||||
import { Request, Response } from 'express';
|
||||
import { LoggerService } from '../../services/logger.service.js';
|
||||
import { GlobalPreferencesService } from '../../services/preferences/index.js';
|
||||
import { MeetStorageService } from '../../services/storage/index.js';
|
||||
import { OpenViduMeetError } from '../../models/error.model.js';
|
||||
|
||||
export const updateRoomPreferences = async (req: Request, res: Response) => {
|
||||
@ -11,7 +11,7 @@ export const updateRoomPreferences = async (req: Request, res: Response) => {
|
||||
const { roomId, roomPreferences } = req.body;
|
||||
|
||||
try {
|
||||
const preferenceService = container.get(GlobalPreferencesService);
|
||||
const preferenceService = container.get(MeetStorageService);
|
||||
preferenceService.validateRoomPreferences(roomPreferences);
|
||||
|
||||
const savedPreferences = await preferenceService.updateOpenViduRoomPreferences(roomId, roomPreferences);
|
||||
@ -35,7 +35,7 @@ export const getRoomPreferences = async (req: Request, res: Response) => {
|
||||
|
||||
try {
|
||||
const { roomId } = req.params;
|
||||
const preferenceService = container.get(GlobalPreferencesService);
|
||||
const preferenceService = container.get(MeetStorageService);
|
||||
const preferences = await preferenceService.getOpenViduRoomPreferences(roomId);
|
||||
|
||||
if (!preferences) {
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { container } from '../../config/dependency-injector.config.js';
|
||||
import { Request, Response } from 'express';
|
||||
import { LoggerService } from '../../services/logger.service.js';
|
||||
import { GlobalPreferencesService } from '../../services/preferences/index.js';
|
||||
import { MeetStorageService } from '../../services/storage/index.js';
|
||||
import { OpenViduMeetError } from '../../models/error.model.js';
|
||||
import { SecurityPreferencesDTO, UpdateSecurityPreferencesDTO } from '@typings-ce';
|
||||
|
||||
export const updateSecurityPreferences = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const globalPrefService = container.get(GlobalPreferencesService);
|
||||
const globalPrefService = container.get(MeetStorageService);
|
||||
|
||||
logger.verbose(`Updating security preferences: ${JSON.stringify(req.body)}`);
|
||||
const securityPreferences = req.body as UpdateSecurityPreferencesDTO;
|
||||
@ -43,7 +43,7 @@ export const updateSecurityPreferences = async (req: Request, res: Response) =>
|
||||
|
||||
export const getSecurityPreferences = async (_req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const preferenceService = container.get(GlobalPreferencesService);
|
||||
const preferenceService = container.get(MeetStorageService);
|
||||
|
||||
try {
|
||||
const preferences = await preferenceService.getGlobalPreferences();
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { container } from '../../config/dependency-injector.config.js';
|
||||
import { Request, Response } from 'express';
|
||||
import { LoggerService } from '../../services/logger.service.js';
|
||||
import { GlobalPreferencesService } from '../../services/preferences/index.js';
|
||||
import { MeetStorageService } from '../../services/storage/index.js';
|
||||
import { OpenViduMeetError } from '../../models/error.model.js';
|
||||
import { WebhookPreferences } from '@typings-ce';
|
||||
|
||||
export const updateWebhookPreferences = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const globalPrefService = container.get(GlobalPreferencesService);
|
||||
const globalPrefService = container.get(MeetStorageService);
|
||||
|
||||
logger.verbose(`Updating webhooks preferences: ${JSON.stringify(req.body)}`);
|
||||
const webhookPreferences = req.body as WebhookPreferences;
|
||||
@ -31,7 +31,7 @@ export const updateWebhookPreferences = async (req: Request, res: Response) => {
|
||||
|
||||
export const getWebhookPreferences = async (_req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const preferenceService = container.get(GlobalPreferencesService);
|
||||
const preferenceService = container.get(MeetStorageService);
|
||||
|
||||
try {
|
||||
const preferences = await preferenceService.getGlobalPreferences();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { AuthMode, ParticipantRole, UserRole, TokenOptions } from '@typings-ce';
|
||||
import { container } from '../config/dependency-injector.config.js';
|
||||
import { GlobalPreferencesService, LoggerService, RoomService } from '../services/index.js';
|
||||
import { MeetStorageService, LoggerService, RoomService } from '../services/index.js';
|
||||
import { allowAnonymous, tokenAndRoleValidator, withAuth } from './auth.middleware.js';
|
||||
|
||||
/**
|
||||
@ -13,7 +13,7 @@ import { allowAnonymous, tokenAndRoleValidator, withAuth } from './auth.middlewa
|
||||
*/
|
||||
export const configureTokenAuth = async (req: Request, res: Response, next: NextFunction) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const globalPrefService = container.get(GlobalPreferencesService);
|
||||
const globalPrefService = container.get(MeetStorageService);
|
||||
const roomService = container.get(RoomService);
|
||||
|
||||
let role: ParticipantRole;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { container } from '../config/dependency-injector.config.js';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { LoggerService } from '../services/logger.service.js';
|
||||
import { GlobalPreferencesService } from '../services/index.js';
|
||||
import { MeetStorageService } from '../services/index.js';
|
||||
import { allowAnonymous, apiKeyValidator, tokenAndRoleValidator, withAuth } from './auth.middleware.js';
|
||||
import { AuthMode, ParticipantRole, UserRole } from '@typings-ce';
|
||||
|
||||
@ -14,7 +14,7 @@ import { AuthMode, ParticipantRole, UserRole } from '@typings-ce';
|
||||
*/
|
||||
export const configureCreateRoomAuth = async (req: Request, res: Response, next: NextFunction) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const globalPrefService = container.get(GlobalPreferencesService);
|
||||
const globalPrefService = container.get(MeetStorageService);
|
||||
let allowRoomCreation: boolean;
|
||||
let requireAuthentication: boolean;
|
||||
|
||||
@ -70,7 +70,7 @@ export const configureRoomAuthorization = async (req: Request, res: Response, ne
|
||||
}
|
||||
|
||||
const logger = container.get(LoggerService);
|
||||
const globalPrefService = container.get(GlobalPreferencesService);
|
||||
const globalPrefService = container.get(MeetStorageService);
|
||||
let authMode: AuthMode;
|
||||
|
||||
try {
|
||||
|
||||
@ -25,7 +25,7 @@ import {
|
||||
recordingRouter,
|
||||
roomRouter
|
||||
} from './routes/index.js';
|
||||
import { GlobalPreferencesService } from './services/index.js';
|
||||
import { MeetStorageService } from './services/index.js';
|
||||
import { internalParticipantsRouter } from './routes/participants.routes.js';
|
||||
import cookieParser from 'cookie-parser';
|
||||
|
||||
@ -76,7 +76,7 @@ const createApp = () => {
|
||||
};
|
||||
|
||||
const initializeGlobalPreferences = async () => {
|
||||
const globalPreferencesService = container.get(GlobalPreferencesService);
|
||||
const globalPreferencesService = container.get(MeetStorageService);
|
||||
// TODO: This should be invoked in the constructor of the service
|
||||
await globalPreferencesService.ensurePreferencesInitialized();
|
||||
};
|
||||
|
||||
@ -2,7 +2,7 @@ import { MEET_ADMIN_SECRET, MEET_ADMIN_USER } from '../environment.js';
|
||||
import { inject, injectable } from '../config/dependency-injector.config.js';
|
||||
import { User } from '@typings-ce';
|
||||
import { UserService } from './user.service.js';
|
||||
import { GlobalPreferencesService } from './preferences/global-preferences.service.js';
|
||||
import { MeetStorageService } from './storage/storage.service.js';
|
||||
import { LoggerService } from './logger.service.js';
|
||||
import { PasswordHelper } from '../helpers/password.helper.js';
|
||||
|
||||
@ -11,7 +11,7 @@ export class AuthService {
|
||||
constructor(
|
||||
@inject(LoggerService) protected logger: LoggerService,
|
||||
@inject(UserService) protected userService: UserService,
|
||||
@inject(GlobalPreferencesService) protected globalPrefService: GlobalPreferencesService
|
||||
@inject(MeetStorageService) protected globalPrefService: MeetStorageService
|
||||
) {}
|
||||
|
||||
async authenticate(username: string, password: string): Promise<User | null> {
|
||||
|
||||
@ -10,9 +10,9 @@ export * from './openvidu-webhook.service.js';
|
||||
export * from './system-event.service.js';
|
||||
export * from './task-scheduler.service.js';
|
||||
export * from './mutex.service.js';
|
||||
export * from './preferences/index.js';
|
||||
export * from './storage/index.js';
|
||||
export * from './redis.service.js';
|
||||
export * from './s3.service.js';
|
||||
export * from './preferences/s3-preferences-storage.js';
|
||||
export * from './storage/providers/s3-storage.js';
|
||||
export * from './token.service.js';
|
||||
export * from './user.service.js';
|
||||
|
||||
@ -10,13 +10,13 @@ import {
|
||||
MeetWebhookPayload,
|
||||
WebhookPreferences
|
||||
} from '@typings-ce';
|
||||
import { GlobalPreferencesService } from './preferences/global-preferences.service.js';
|
||||
import { MeetStorageService } from './storage/storage.service.js';
|
||||
|
||||
@injectable()
|
||||
export class OpenViduWebhookService {
|
||||
constructor(
|
||||
@inject(LoggerService) protected logger: LoggerService,
|
||||
@inject(GlobalPreferencesService) protected globalPrefService: GlobalPreferencesService
|
||||
@inject(MeetStorageService) protected globalPrefService: MeetStorageService
|
||||
) {}
|
||||
|
||||
// TODO: Implement Room webhooks
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Factory class to determine and instantiate the appropriate preferences storage
|
||||
* mechanism (e.g., Database or S3), based on the configuration of the application.
|
||||
*/
|
||||
|
||||
import { PreferencesStorage } from './global-preferences-storage.interface.js';
|
||||
import { S3PreferenceStorage } from './s3-preferences-storage.js';
|
||||
import { MEET_PREFERENCES_STORAGE_MODE } from '../../environment.js';
|
||||
import { inject, injectable } from '../../config/dependency-injector.config.js';
|
||||
import { LoggerService } from '../logger.service.js';
|
||||
|
||||
@injectable()
|
||||
export class GlobalPreferencesStorageFactory {
|
||||
constructor(
|
||||
@inject(S3PreferenceStorage) protected s3PreferenceStorage: S3PreferenceStorage,
|
||||
@inject(LoggerService) protected logger: LoggerService
|
||||
) {}
|
||||
|
||||
create(): PreferencesStorage {
|
||||
const storageMode = MEET_PREFERENCES_STORAGE_MODE;
|
||||
|
||||
switch (storageMode) {
|
||||
case 's3':
|
||||
return this.s3PreferenceStorage;
|
||||
|
||||
default:
|
||||
this.logger.info('No preferences storage mode specified. Defaulting to S3.');
|
||||
return this.s3PreferenceStorage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
export * from './global-preferences.service.js';
|
||||
export * from './global-preferences-storage.interface.js';
|
||||
export * from './global-preferences.factory.js';
|
||||
4
backend/src/services/storage/index.ts
Normal file
4
backend/src/services/storage/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './storage.service.js';
|
||||
export * from './storage.interface.js';
|
||||
export * from './storage.factory.js';
|
||||
export * from './providers/s3-storage.js';
|
||||
@ -1,23 +1,33 @@
|
||||
/**
|
||||
* Implements storage for preferences using S3.
|
||||
* This is used when the application is configured to operate in "s3" mode.
|
||||
*/
|
||||
|
||||
import { GlobalPreferences, MeetRoom } from '@typings-ce';
|
||||
import { PreferencesStorage } from './global-preferences-storage.interface.js';
|
||||
import { S3Service } from '../s3.service.js';
|
||||
import { LoggerService } from '../logger.service.js';
|
||||
import { RedisService } from '../redis.service.js';
|
||||
import { OpenViduMeetError } from '../../models/error.model.js';
|
||||
import { inject, injectable } from '../../config/dependency-injector.config.js';
|
||||
import { MEET_S3_ROOMS_PREFIX } from '../../environment.js';
|
||||
import { StorageProvider } from '../storage.interface.js';
|
||||
import { S3Service } from '../../s3.service.js';
|
||||
import { LoggerService } from '../../logger.service.js';
|
||||
import { RedisService } from '../../redis.service.js';
|
||||
import { OpenViduMeetError } from '../../../models/error.model.js';
|
||||
import { inject, injectable } from '../../../config/dependency-injector.config.js';
|
||||
import { MEET_S3_ROOMS_PREFIX } from '../../../environment.js';
|
||||
|
||||
// TODO Rename this service to MeetStorageService?
|
||||
|
||||
/**
|
||||
* Implementation of the StorageProvider interface using AWS S3 for persistent storage
|
||||
* with Redis caching for improved performance.
|
||||
*
|
||||
* This class provides operations for storing and retrieving application preferences and room data
|
||||
* with a two-tiered storage approach:
|
||||
* - Redis is used as a primary cache for fast access
|
||||
* - S3 serves as the persistent storage layer and fallback when data is not in Redis
|
||||
*
|
||||
* The storage operations are performed in parallel to both systems when writing data,
|
||||
* with transaction-like rollback behavior if one operation fails.
|
||||
*
|
||||
* @template G - Type for global preferences data, defaults to GlobalPreferences
|
||||
* @template R - Type for room data, defaults to MeetRoom
|
||||
*
|
||||
* @implements {StorageProvider}
|
||||
*/
|
||||
@injectable()
|
||||
export class S3PreferenceStorage<
|
||||
G extends GlobalPreferences = GlobalPreferences,
|
||||
R extends MeetRoom = MeetRoom
|
||||
> implements PreferencesStorage
|
||||
export class S3Storage<G extends GlobalPreferences = GlobalPreferences, R extends MeetRoom = MeetRoom>
|
||||
implements StorageProvider
|
||||
{
|
||||
protected readonly GLOBAL_PREFERENCES_KEY = 'openvidu-meet-preferences';
|
||||
constructor(
|
||||
@ -79,7 +89,7 @@ export class S3PreferenceStorage<
|
||||
}
|
||||
}
|
||||
|
||||
async saveOpenViduRoom(ovRoom: R): Promise<R> {
|
||||
async saveMeetRoom(ovRoom: R): Promise<R> {
|
||||
const { roomId } = ovRoom;
|
||||
const s3Path = `${MEET_S3_ROOMS_PREFIX}/${roomId}/${roomId}.json`;
|
||||
const roomStr = JSON.stringify(ovRoom);
|
||||
@ -122,21 +132,34 @@ export class S3PreferenceStorage<
|
||||
throw error;
|
||||
}
|
||||
|
||||
async getOpenViduRooms(): Promise<R[]> {
|
||||
async getMeetRooms(
|
||||
maxItems: number,
|
||||
nextPageToken?: string
|
||||
): Promise<{
|
||||
rooms: R[];
|
||||
isTruncated: boolean;
|
||||
nextPageToken?: string;
|
||||
}> {
|
||||
try {
|
||||
const content = await this.s3Service.listObjects(MEET_S3_ROOMS_PREFIX);
|
||||
const roomFiles =
|
||||
content.Contents?.filter(
|
||||
(file) =>
|
||||
file?.Key?.endsWith('.json') &&
|
||||
file.Key !== `${this.GLOBAL_PREFERENCES_KEY}.json`
|
||||
) ?? [];
|
||||
const {
|
||||
Contents: roomFiles,
|
||||
IsTruncated,
|
||||
NextContinuationToken
|
||||
} = await this.s3Service.listObjectsPaginated(MEET_S3_ROOMS_PREFIX, maxItems, nextPageToken);
|
||||
|
||||
if (roomFiles.length === 0) {
|
||||
this.logger.verbose('No OpenVidu rooms found in S3');
|
||||
return [];
|
||||
if (!roomFiles) {
|
||||
this.logger.verbose('No rooms found. Returning an empty array.');
|
||||
return { rooms: [], isTruncated: false };
|
||||
}
|
||||
|
||||
// const promises: Promise<R>[] = [];
|
||||
// // Retrieve the data for each room
|
||||
// roomFiles.forEach((item) => {
|
||||
// if (item?.Key && item.Key.endsWith('.json')) {
|
||||
// promises.push(getOpenViduRoom(item.Key) as Promise<R>);
|
||||
// }
|
||||
// });
|
||||
|
||||
// Extract room names from file paths
|
||||
const roomIds = roomFiles.map((file) => this.extractRoomId(file.Key)).filter(Boolean) as string[];
|
||||
// Fetch room preferences in parallel
|
||||
@ -145,7 +168,7 @@ export class S3PreferenceStorage<
|
||||
if (!roomId) return null;
|
||||
|
||||
try {
|
||||
return await this.getOpenViduRoom(roomId);
|
||||
return await this.getMeetRoom(roomId);
|
||||
} catch (error: any) {
|
||||
this.logger.warn(`Failed to fetch room "${roomId}": ${error.message}`);
|
||||
return null;
|
||||
@ -154,10 +177,11 @@ export class S3PreferenceStorage<
|
||||
);
|
||||
|
||||
// Filter out null values
|
||||
return rooms.filter(Boolean) as R[];
|
||||
const roomsResponse = rooms.filter(Boolean) as R[];
|
||||
return { rooms: roomsResponse, isTruncated: !!IsTruncated, nextPageToken: NextContinuationToken };
|
||||
} catch (error) {
|
||||
this.handleError(error, 'Error fetching Room preferences');
|
||||
return [];
|
||||
return { rooms: [], isTruncated: false };
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +205,7 @@ export class S3PreferenceStorage<
|
||||
return parts[parts.length - 2];
|
||||
}
|
||||
|
||||
async getOpenViduRoom(roomId: string): Promise<R | null> {
|
||||
async getMeetRoom(roomId: string): Promise<R | null> {
|
||||
try {
|
||||
const room: R | null = await this.getFromRedis<R>(roomId);
|
||||
|
||||
@ -198,7 +222,7 @@ export class S3PreferenceStorage<
|
||||
}
|
||||
}
|
||||
|
||||
async deleteOpenViduRoom(roomId: string): Promise<void> {
|
||||
async deleteMeetRoom(roomId: string): Promise<void> {
|
||||
try {
|
||||
await Promise.all([
|
||||
this.s3Service.deleteObject(`${MEET_S3_ROOMS_PREFIX}/${roomId}/${roomId}.json`),
|
||||
32
backend/src/services/storage/storage.factory.ts
Normal file
32
backend/src/services/storage/storage.factory.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { StorageProvider } from './storage.interface.js';
|
||||
import { S3Storage } from './providers/s3-storage.js';
|
||||
import { MEET_PREFERENCES_STORAGE_MODE } from '../../environment.js';
|
||||
import { inject, injectable } from '../../config/dependency-injector.config.js';
|
||||
import { LoggerService } from '../logger.service.js';
|
||||
|
||||
/**
|
||||
* Factory class responsible for creating the appropriate storage provider based on configuration.
|
||||
*
|
||||
* This factory determines which storage implementation to use based on the `MEET_PREFERENCES_STORAGE_MODE`
|
||||
* environment variable. Currently supports S3 storage, with more providers potentially added in the future.
|
||||
*/
|
||||
@injectable()
|
||||
export class StorageFactory {
|
||||
constructor(
|
||||
@inject(S3Storage) protected s3Storage: S3Storage,
|
||||
@inject(LoggerService) protected logger: LoggerService
|
||||
) {}
|
||||
|
||||
create(): StorageProvider {
|
||||
const storageMode = MEET_PREFERENCES_STORAGE_MODE;
|
||||
|
||||
switch (storageMode) {
|
||||
case 's3':
|
||||
return this.s3Storage;
|
||||
|
||||
default:
|
||||
this.logger.info('No preferences storage mode specified. Defaulting to S3.');
|
||||
return this.s3Storage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,17 @@
|
||||
import { GlobalPreferences, MeetRoom } from '@typings-ce';
|
||||
|
||||
/**
|
||||
* Interface for managing global preferences storage.
|
||||
* An interface that defines the contract for storage providers in the OpenVidu Meet application.
|
||||
* Storage providers handle persistence of global application preferences and meeting room data.
|
||||
*
|
||||
* @template T - The type of global preferences, extending GlobalPreferences
|
||||
* @template R - The type of room data, extending MeetRoom
|
||||
*
|
||||
* Implementations of this interface should handle the persistent storage
|
||||
* of application settings and room information, which could be backed by
|
||||
* various storage solutions (database, file system, cloud storage, etc.).
|
||||
*/
|
||||
|
||||
export interface PreferencesStorage<
|
||||
T extends GlobalPreferences = GlobalPreferences,
|
||||
R extends MeetRoom = MeetRoom
|
||||
> {
|
||||
export interface StorageProvider<T extends GlobalPreferences = GlobalPreferences, R extends MeetRoom = MeetRoom> {
|
||||
/**
|
||||
* Initializes the storage with default preferences if they are not already set.
|
||||
*
|
||||
@ -31,7 +35,14 @@ export interface PreferencesStorage<
|
||||
*/
|
||||
saveGlobalPreferences(preferences: T): Promise<T>;
|
||||
|
||||
getOpenViduRooms(): Promise<R[]>;
|
||||
getMeetRooms(
|
||||
maxItems?: number,
|
||||
nextPageToken?: string
|
||||
): Promise<{
|
||||
rooms: R[];
|
||||
isTruncated: boolean;
|
||||
nextPageToken?: string;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Retrieves the {@link MeetRoom}.
|
||||
@ -39,21 +50,21 @@ export interface PreferencesStorage<
|
||||
* @param roomId - The name of the room to retrieve.
|
||||
* @returns A promise that resolves to the OpenVidu Room, or null if not found.
|
||||
**/
|
||||
getOpenViduRoom(roomId: string): Promise<R | null>;
|
||||
getMeetRoom(roomId: string): Promise<R | null>;
|
||||
|
||||
/**
|
||||
* Saves the OpenVidu Room.
|
||||
* Saves the OpenVidu Meet Room.
|
||||
*
|
||||
* @param ovRoom - The OpenVidu Room to save.
|
||||
* @returns A promise that resolves to the saved
|
||||
**/
|
||||
saveOpenViduRoom(ovRoom: R): Promise<R>;
|
||||
saveMeetRoom(ovRoom: R): Promise<R>;
|
||||
|
||||
/**
|
||||
* Deletes the OpenVidu Room for a given room name.
|
||||
* Deletes the OpenVidu Meet Room for a given room name.
|
||||
*
|
||||
* @param roomId - The name of the room whose should be deleted.
|
||||
* @returns A promise that resolves when the room have been deleted.
|
||||
**/
|
||||
deleteOpenViduRoom(roomId: string): Promise<void>;
|
||||
deleteMeetRoom(roomId: string): Promise<void>;
|
||||
}
|
||||
@ -1,28 +1,29 @@
|
||||
/**
|
||||
* Service that provides high-level methods for managing application preferences,
|
||||
* regardless of the underlying storage mechanism.
|
||||
*/
|
||||
|
||||
import { AuthMode, AuthType, GlobalPreferences, MeetRoom, MeetRoomPreferences } from '@typings-ce';
|
||||
import { LoggerService } from '../logger.service.js';
|
||||
import { PreferencesStorage } from './global-preferences-storage.interface.js';
|
||||
import { GlobalPreferencesStorageFactory } from './global-preferences.factory.js';
|
||||
import { StorageProvider } from './storage.interface.js';
|
||||
import { StorageFactory } from './storage.factory.js';
|
||||
import { errorRoomNotFound, OpenViduMeetError } from '../../models/error.model.js';
|
||||
import { MEET_NAME_ID, MEET_SECRET, MEET_USER, MEET_WEBHOOK_ENABLED, MEET_WEBHOOK_URL } from '../../environment.js';
|
||||
import { injectable, inject } from '../../config/dependency-injector.config.js';
|
||||
import { PasswordHelper } from '../../helpers/password.helper.js';
|
||||
|
||||
/**
|
||||
* A service for managing storage operations related to OpenVidu Meet rooms and preferences.
|
||||
*
|
||||
* This service provides an abstraction layer over the underlying storage implementation,
|
||||
* handling initialization, retrieval, and persistence of global preferences and room data.
|
||||
*
|
||||
* @typeParam G - Type for global preferences, extends GlobalPreferences
|
||||
* @typeParam R - Type for room data, extends MeetRoom
|
||||
*/
|
||||
@injectable()
|
||||
export class GlobalPreferencesService<
|
||||
G extends GlobalPreferences = GlobalPreferences,
|
||||
R extends MeetRoom = MeetRoom
|
||||
> {
|
||||
protected storage: PreferencesStorage;
|
||||
export class MeetStorageService<G extends GlobalPreferences = GlobalPreferences, R extends MeetRoom = MeetRoom> {
|
||||
protected storageProvider: StorageProvider;
|
||||
constructor(
|
||||
@inject(LoggerService) protected logger: LoggerService,
|
||||
@inject(GlobalPreferencesStorageFactory) protected storageFactory: GlobalPreferencesStorageFactory
|
||||
@inject(StorageFactory) protected storageFactory: StorageFactory
|
||||
) {
|
||||
this.storage = this.storageFactory.create();
|
||||
this.storageProvider = this.storageFactory.create();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,7 +34,7 @@ export class GlobalPreferencesService<
|
||||
const preferences = await this.getDefaultPreferences();
|
||||
|
||||
try {
|
||||
await this.storage.initialize(preferences);
|
||||
await this.storageProvider.initialize(preferences);
|
||||
return preferences as G;
|
||||
} catch (error) {
|
||||
this.handleError(error, 'Error initializing default preferences');
|
||||
@ -46,7 +47,7 @@ export class GlobalPreferencesService<
|
||||
* @returns {Promise<GlobalPreferences>}
|
||||
*/
|
||||
async getGlobalPreferences(): Promise<G> {
|
||||
const preferences = await this.storage.getGlobalPreferences();
|
||||
const preferences = await this.storageProvider.getGlobalPreferences();
|
||||
|
||||
if (preferences) return preferences as G;
|
||||
|
||||
@ -60,16 +61,27 @@ export class GlobalPreferencesService<
|
||||
*/
|
||||
async saveGlobalPreferences(preferences: G): Promise<G> {
|
||||
this.logger.info('Saving global preferences');
|
||||
return this.storage.saveGlobalPreferences(preferences) as Promise<G>;
|
||||
return this.storageProvider.saveGlobalPreferences(preferences) as Promise<G>;
|
||||
}
|
||||
|
||||
async saveOpenViduRoom(ovRoom: R): Promise<R> {
|
||||
this.logger.info(`Saving OpenVidu room ${ovRoom.roomId}`);
|
||||
return this.storage.saveOpenViduRoom(ovRoom) as Promise<R>;
|
||||
return this.storageProvider.saveMeetRoom(ovRoom) as Promise<R>;
|
||||
}
|
||||
|
||||
async getOpenViduRooms(): Promise<R[]> {
|
||||
return this.storage.getOpenViduRooms() as Promise<R[]>;
|
||||
async getOpenViduRooms(
|
||||
maxItems?: number,
|
||||
nextPageToken?: string
|
||||
): Promise<{
|
||||
rooms: R[];
|
||||
isTruncated: boolean;
|
||||
nextPageToken?: string;
|
||||
}> {
|
||||
return this.storageProvider.getMeetRooms(maxItems, nextPageToken) as Promise<{
|
||||
rooms: R[];
|
||||
isTruncated: boolean;
|
||||
nextPageToken?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,7 +92,7 @@ export class GlobalPreferencesService<
|
||||
* @throws Error if the room preferences are not found.
|
||||
*/
|
||||
async getOpenViduRoom(roomId: string): Promise<R> {
|
||||
const openviduRoom = await this.storage.getOpenViduRoom(roomId);
|
||||
const openviduRoom = await this.storageProvider.getMeetRoom(roomId);
|
||||
|
||||
if (!openviduRoom) {
|
||||
this.logger.error(`Room not found for room ${roomId}`);
|
||||
@ -91,7 +103,7 @@ export class GlobalPreferencesService<
|
||||
}
|
||||
|
||||
async deleteOpenViduRoom(roomId: string): Promise<void> {
|
||||
return this.storage.deleteOpenViduRoom(roomId);
|
||||
return this.storageProvider.deleteMeetRoom(roomId);
|
||||
}
|
||||
|
||||
async getOpenViduRoomPreferences(roomId: string): Promise<MeetRoomPreferences> {
|
||||
@ -177,7 +189,7 @@ export class GlobalPreferencesService<
|
||||
* @param {any} error
|
||||
* @param {string} message
|
||||
*/
|
||||
protected handleError(error: any, message: string) {
|
||||
protected handleError(error: OpenViduMeetError | unknown, message: string) {
|
||||
if (error instanceof OpenViduMeetError) {
|
||||
this.logger.error(`${message}: ${error.message}`);
|
||||
} else {
|
||||
@ -2,13 +2,13 @@ import { MEET_ADMIN_USER } from '../environment.js';
|
||||
import { inject, injectable } from '../config/dependency-injector.config.js';
|
||||
import { UserRole, SingleUserAuth, User, SingleUserCredentials } from '@typings-ce';
|
||||
import { LoggerService } from './logger.service.js';
|
||||
import { GlobalPreferencesService } from './preferences/global-preferences.service.js';
|
||||
import { MeetStorageService } from './storage/storage.service.js';
|
||||
|
||||
@injectable()
|
||||
export class UserService {
|
||||
constructor(
|
||||
@inject(LoggerService) protected logger: LoggerService,
|
||||
@inject(GlobalPreferencesService) protected globalPrefService: GlobalPreferencesService
|
||||
@inject(MeetStorageService) protected globalPrefService: MeetStorageService
|
||||
) {}
|
||||
|
||||
async getUser(username: string): Promise<User | null> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user