Rename OpenViduMeetRoomOptions and OpenViduMeetRoom to MeetRoomOptions and MeetRoom

This commit is contained in:
Carlos Santos 2025-03-31 15:20:25 +02:00
parent bea36272af
commit fef7e50555
14 changed files with 74 additions and 70 deletions

View File

@ -3,12 +3,12 @@ import { Request, Response } from 'express';
import { LoggerService } from '../services/logger.service.js';
import { OpenViduMeetError } from '../models/error.model.js';
import { RoomService } from '../services/room.service.js';
import { OpenViduMeetRoomOptions } from '@typings-ce';
import { MeetRoomOptions } from '@typings-ce';
export const createRoom = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const roomService = container.get(RoomService);
const options: OpenViduMeetRoomOptions = req.body;
const options: MeetRoomOptions = req.body;
try {
logger.verbose(`Creating room with options '${JSON.stringify(options)}'`);

View File

@ -1,20 +1,20 @@
import { OpenViduMeetRoom, OpenViduMeetRoomOptions } from '@typings-ce';
import { MeetRoom, MeetRoomOptions } from '@typings-ce';
import { CreateOptions } from 'livekit-server-sdk';
import { MEET_NAME_ID } from '../environment.js';
import { uid } from 'uid/single';
export class OpenViduRoomHelper {
export class MeetRoomHelper {
private constructor() {
// Prevent instantiation of this utility class
}
/**
* Converts an OpenViduMeetRoom object to an OpenViduMeetRoomOptions object.
* Converts an MeetRoom object to an MeetRoomOptions object.
*
* @param room - The OpenViduMeetRoom object to convert.
* @returns An OpenViduMeetRoomOptions object containing the same properties as the input room.
* @param room - The MeetRoom object to convert.
* @returns An MeetRoomOptions object containing the same properties as the input room.
*/
static toOpenViduOptions(room: OpenViduMeetRoom): OpenViduMeetRoomOptions {
static toOpenViduOptions(room: MeetRoom): MeetRoomOptions {
return {
expirationDate: room.expirationDate,
maxParticipants: room.maxParticipants,
@ -23,7 +23,7 @@ export class OpenViduRoomHelper {
};
}
static generateLivekitRoomOptions(roomInput: OpenViduMeetRoom | OpenViduMeetRoomOptions): CreateOptions {
static generateLivekitRoomOptions(roomInput: MeetRoom | MeetRoomOptions): CreateOptions {
const isOpenViduRoom = 'creationDate' in roomInput;
const sanitizedPrefix = roomInput.roomNamePrefix
?.trim()
@ -35,7 +35,7 @@ export class OpenViduRoomHelper {
expirationDate,
maxParticipants,
creationDate = Date.now()
} = roomInput as OpenViduMeetRoom;
} = roomInput as MeetRoom;
const timeUntilExpiration = this.calculateExpirationTime(expirationDate, creationDate);
@ -44,7 +44,7 @@ export class OpenViduRoomHelper {
metadata: JSON.stringify({
createdBy: MEET_NAME_ID,
roomOptions: isOpenViduRoom
? OpenViduRoomHelper.toOpenViduOptions(roomInput as OpenViduMeetRoom)
? MeetRoomHelper.toOpenViduOptions(roomInput as MeetRoom)
: roomInput
}),
emptyTimeout: timeUntilExpiration,

View File

@ -1,6 +1,6 @@
import { container } from '../config/dependency-injector.config.js';
import { Request, Response, NextFunction } from 'express';
import { OpenViduMeetPermissions, OpenViduMeetRoom } from '@typings-ce';
import { OpenViduMeetPermissions, MeetRoom } from '@typings-ce';
import { LoggerService } from '../services/logger.service.js';
import { RoomService } from '../services/room.service.js';
import { RecordingHelper } from '../helpers/recording.helper.js';
@ -18,7 +18,7 @@ export const withRecordingEnabled = async (req: Request, res: Response, next: Ne
({ roomId } = RecordingHelper.extractInfoFromRecordingId(recordingId));
}
let room: OpenViduMeetRoom;
let room: MeetRoom;
try {
const roomService = container.get(RoomService);

View File

@ -1,6 +1,6 @@
import {
ChatPreferences,
OpenViduMeetRoomOptions,
MeetRoomOptions,
RecordingPreferences,
RoomPreferences,
VirtualBackgroundPreferences
@ -26,7 +26,7 @@ const RoomPreferencesSchema: z.ZodType<RoomPreferences> = z.object({
virtualBackgroundPreferences: VirtualBackgroundPreferencesSchema
});
const RoomRequestOptionsSchema: z.ZodType<OpenViduMeetRoomOptions> = z.object({
const RoomRequestOptionsSchema: z.ZodType<MeetRoomOptions> = z.object({
expirationDate: z
.number()
.positive('Expiration date must be a positive integer')

View File

@ -1,4 +1,4 @@
import { GlobalPreferences, OpenViduMeetRoom } from '@typings-ce';
import { GlobalPreferences, MeetRoom } from '@typings-ce';
/**
* Interface for managing global preferences storage.
@ -6,7 +6,7 @@ import { GlobalPreferences, OpenViduMeetRoom } from '@typings-ce';
export interface PreferencesStorage<
T extends GlobalPreferences = GlobalPreferences,
R extends OpenViduMeetRoom = OpenViduMeetRoom
R extends MeetRoom = MeetRoom
> {
/**
* Initializes the storage with default preferences if they are not already set.
@ -34,7 +34,7 @@ export interface PreferencesStorage<
getOpenViduRooms(): Promise<R[]>;
/**
* Retrieves the {@link OpenViduMeetRoom}.
* Retrieves the {@link MeetRoom}.
*
* @param roomName - The name of the room to retrieve.
* @returns A promise that resolves to the OpenVidu Room, or null if not found.

View File

@ -3,7 +3,7 @@
* regardless of the underlying storage mechanism.
*/
import { AuthMode, AuthType, GlobalPreferences, OpenViduMeetRoom, RoomPreferences } from '@typings-ce';
import { AuthMode, AuthType, GlobalPreferences, MeetRoom, RoomPreferences } from '@typings-ce';
import { LoggerService } from '../logger.service.js';
import { PreferencesStorage } from './global-preferences-storage.interface.js';
import { GlobalPreferencesStorageFactory } from './global-preferences.factory.js';
@ -15,7 +15,7 @@ import { PasswordHelper } from '../../helpers/password.helper.js';
@injectable()
export class GlobalPreferencesService<
G extends GlobalPreferences = GlobalPreferences,
R extends OpenViduMeetRoom = OpenViduMeetRoom
R extends MeetRoom = MeetRoom
> {
protected storage: PreferencesStorage;
constructor(

View File

@ -3,21 +3,22 @@
* This is used when the application is configured to operate in "s3" mode.
*/
import { GlobalPreferences, OpenViduMeetRoom } from '@typings-ce';
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';
// TODO Rename this service to MeetStorageService?
@injectable()
export class S3PreferenceStorage<
G extends GlobalPreferences = GlobalPreferences,
R extends OpenViduMeetRoom = OpenViduMeetRoom
R extends MeetRoom = MeetRoom
> implements PreferencesStorage
{
protected readonly PREFERENCES_PATH = '.openvidu-meet';
protected readonly GLOBAL_PREFERENCES_KEY = 'openvidu-meet-preferences';
constructor(
@inject(LoggerService) protected logger: LoggerService,
@ -49,9 +50,10 @@ export class S3PreferenceStorage<
if (!preferences) {
// Fallback to fetching from S3 if Redis doesn't have it
this.logger.debug('Preferences not found in Redis. Fetching from S3...');
preferences = await this.getFromS3<G>(`${this.PREFERENCES_PATH}/${this.GLOBAL_PREFERENCES_KEY}.json`);
preferences = await this.getFromS3<G>(`${this.GLOBAL_PREFERENCES_KEY}.json`);
if (preferences) {
// TODO: Use a key prefix for Redis
await this.redisService.set(this.GLOBAL_PREFERENCES_KEY, JSON.stringify(preferences), false);
}
}
@ -66,7 +68,8 @@ export class S3PreferenceStorage<
async saveGlobalPreferences(preferences: G): Promise<G> {
try {
await Promise.all([
this.s3Service.saveObject(`${this.PREFERENCES_PATH}/${this.GLOBAL_PREFERENCES_KEY}.json`, preferences),
this.s3Service.saveObject(`${this.GLOBAL_PREFERENCES_KEY}.json`, preferences),
// TODO: Use a key prefix for Redis
this.redisService.set(this.GLOBAL_PREFERENCES_KEY, JSON.stringify(preferences), false)
]);
return preferences;
@ -78,11 +81,12 @@ export class S3PreferenceStorage<
async saveOpenViduRoom(ovRoom: R): Promise<R> {
const { roomName } = ovRoom;
const s3Path = `${this.PREFERENCES_PATH}/${roomName}/${roomName}.json`;
const s3Path = `${MEET_S3_ROOMS_PREFIX}/${roomName}/${roomName}.json`;
const roomStr = JSON.stringify(ovRoom);
const results = await Promise.allSettled([
this.s3Service.saveObject(s3Path, ovRoom),
// TODO: Use a key prefix for Redis
this.redisService.set(roomName, roomStr, false)
]);
@ -120,12 +124,12 @@ export class S3PreferenceStorage<
async getOpenViduRooms(): Promise<R[]> {
try {
const content = await this.s3Service.listObjects(this.PREFERENCES_PATH);
const content = await this.s3Service.listObjects(MEET_S3_ROOMS_PREFIX);
const roomFiles =
content.Contents?.filter(
(file) =>
file?.Key?.endsWith('.json') &&
file.Key !== `${this.PREFERENCES_PATH}/${this.GLOBAL_PREFERENCES_KEY}.json`
file.Key !== `${this.GLOBAL_PREFERENCES_KEY}.json`
) ?? [];
if (roomFiles.length === 0) {
@ -177,18 +181,19 @@ export class S3PreferenceStorage<
return parts[parts.length - 2];
}
async getOpenViduRoom(roomName: string): Promise<R | null> {
async getOpenViduRoom(roomId: string): Promise<R | null> {
try {
const room: R | null = await this.getFromRedis<R>(roomName);
const room: R | null = await this.getFromRedis<R>(roomId);
if (!room) {
this.logger.debug(`Room preferences not found in Redis. Fetching from S3...`);
return await this.getFromS3<R>(`${this.PREFERENCES_PATH}/${roomName}/${roomName}.json`);
this.logger.debug(`Room ${roomId} not found in Redis. Fetching from S3...`);
return await this.getFromS3<R>(`${MEET_S3_ROOMS_PREFIX}/${roomId}/${roomId}.json`);
}
this.logger.debug(`Room ${roomId} verified in Redis`);
return room;
} catch (error) {
this.handleError(error, `Error fetching Room preferences for room ${roomName}`);
this.handleError(error, `Error fetching Room preferences for room ${roomId}`);
return null;
}
}
@ -196,7 +201,7 @@ export class S3PreferenceStorage<
async deleteOpenViduRoom(roomName: string): Promise<void> {
try {
await Promise.all([
this.s3Service.deleteObject(`${this.PREFERENCES_PATH}/${roomName}/${roomName}.json`),
this.s3Service.deleteObject(`${MEET_S3_ROOMS_PREFIX}/${roomName}/${roomName}.json`),
this.redisService.delete(roomName)
]);
} catch (error) {
@ -210,7 +215,6 @@ export class S3PreferenceStorage<
response = await this.redisService.get(key);
if (response) {
this.logger.debug(`Object ${key} found in Redis`);
return JSON.parse(response) as U;
}

View File

@ -4,8 +4,8 @@ import { CreateOptions, Room, SendDataOptions } from 'livekit-server-sdk';
import { LoggerService } from './logger.service.js';
import { LiveKitService } from './livekit.service.js';
import { GlobalPreferencesService } from './preferences/global-preferences.service.js';
import { OpenViduMeetRoom, OpenViduMeetRoomOptions, ParticipantRole } from '@typings-ce';
import { OpenViduRoomHelper } from '../helpers/room.helper.js';
import { MeetRoom, MeetRoomOptions, ParticipantRole } from '@typings-ce';
import { MeetRoomHelper } from '../helpers/room.helper.js';
import { SystemEventService } from './system-event.service.js';
import { TaskSchedulerService } from './task-scheduler.service.js';
import { errorParticipantUnauthorized } from '../models/error.model.js';
@ -54,16 +54,16 @@ export class RoomService {
* Creates an OpenVidu room with the specified options.
*
* @param {string} baseUrl - The base URL for the room.
* @param {OpenViduMeetRoomOptions} options - The options for creating the OpenVidu room.
* @returns {Promise<OpenViduMeetRoom>} A promise that resolves to the created OpenVidu room.
* @param {MeetRoomOptions} options - The options for creating the OpenVidu room.
* @returns {Promise<MeetRoom>} A promise that resolves to the created OpenVidu room.
*
* @throws {Error} If the room creation fails.
*
*/
async createRoom(baseUrl: string, roomOptions: OpenViduMeetRoomOptions): Promise<OpenViduMeetRoom> {
async createRoom(baseUrl: string, roomOptions: MeetRoomOptions): Promise<MeetRoom> {
const livekitRoom: Room = await this.createLivekitRoom(roomOptions);
const openviduRoom: OpenViduMeetRoom = this.generateOpenViduRoom(baseUrl, livekitRoom, roomOptions);
const openviduRoom: MeetRoom = this.generateOpenViduRoom(baseUrl, livekitRoom, roomOptions);
await this.globalPrefService.saveOpenViduRoom(openviduRoom);
@ -72,10 +72,10 @@ export class RoomService {
/**
* Retrieves a list of rooms.
* @returns A Promise that resolves to an array of {@link OpenViduMeetRoom} objects.
* @returns A Promise that resolves to an array of {@link MeetRoom} objects.
* @throws If there was an error retrieving the rooms.
*/
async listOpenViduRooms(): Promise<OpenViduMeetRoom[]> {
async listOpenViduRooms(): Promise<MeetRoom[]> {
return await this.globalPrefService.getOpenViduRooms();
}
@ -83,9 +83,9 @@ export class RoomService {
* Retrieves an OpenVidu room by its name.
*
* @param roomName - The name of the room to retrieve.
* @returns A promise that resolves to an {@link OpenViduMeetRoom} object.
* @returns A promise that resolves to an {@link MeetRoom} object.
*/
async getOpenViduRoom(roomName: string): Promise<OpenViduMeetRoom> {
async getOpenViduRoom(roomName: string): Promise<MeetRoom> {
return await this.globalPrefService.getOpenViduRoom(roomName);
}
@ -222,8 +222,8 @@ export class RoomService {
* @param roomOptions - The options for creating the room.
* @returns A promise that resolves to the created room.
*/
protected async createLivekitRoom(roomOptions: OpenViduMeetRoomOptions): Promise<Room> {
const livekitRoomOptions: CreateOptions = OpenViduRoomHelper.generateLivekitRoomOptions(roomOptions);
protected async createLivekitRoom(roomOptions: MeetRoomOptions): Promise<Room> {
const livekitRoomOptions: CreateOptions = MeetRoomHelper.generateLivekitRoomOptions(roomOptions);
return this.livekitService.createRoom(livekitRoomOptions);
}
@ -239,12 +239,12 @@ export class RoomService {
protected generateOpenViduRoom(
baseUrl: string,
livekitRoom: Room,
roomOptions: OpenViduMeetRoomOptions
): OpenViduMeetRoom {
roomOptions: MeetRoomOptions
): MeetRoom {
const { name: roomName, creationTime } = livekitRoom;
const { preferences, expirationDate, roomNamePrefix, maxParticipants } = roomOptions;
const openviduRoom: OpenViduMeetRoom = {
const openviduRoom: MeetRoom = {
roomName,
roomNamePrefix,
creationDate: Number(creationTime) * 1000,
@ -338,7 +338,7 @@ export class RoomService {
]);
let lkRooms: Room[] = [];
let ovRooms: OpenViduMeetRoom[] = [];
let ovRooms: MeetRoom[] = [];
if (lkResult.status === 'fulfilled') {
lkRooms = lkResult.value;
@ -352,7 +352,7 @@ export class RoomService {
this.logger.error('Failed to list OpenVidu rooms:', ovResult.reason);
}
const missingRooms: OpenViduMeetRoom[] = ovRooms.filter(
const missingRooms: MeetRoom[] = ovRooms.filter(
(ovRoom) => !lkRooms.some((room) => room.name === ovRoom.roomName)
);

View File

@ -8,7 +8,7 @@ import { DatePipe } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatListItem, MatListModule } from '@angular/material/list';
import { OpenViduMeetRoom } from 'projects/shared-meet-components/src/lib/typings/ce/room';
import { MeetRoom } from 'projects/shared-meet-components/src/lib/typings/ce/room';
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
@Component({
@ -28,7 +28,7 @@ import { ActivatedRoute, Router, RouterModule } from '@angular/router';
styleUrl: './rooms.component.scss'
})
export class RoomsComponent implements OnInit {
createdRooms: OpenViduMeetRoom[] = [];
createdRooms: MeetRoom[] = [];
// private roomPreferences!: RoomPreferences;
recordingEnabled = false;
chatEnabled = false;
@ -77,7 +77,7 @@ export class RoomsComponent implements OnInit {
window.open(`/${roomName}`, '_blank');
}
deleteRoom(room: OpenViduMeetRoom) {
deleteRoom(room: MeetRoom) {
try {
this.roomService.deleteRoom(room.roomName);
this.createdRooms = this.createdRooms.filter((r) => r.roomName !== room.roomName);
@ -88,7 +88,7 @@ export class RoomsComponent implements OnInit {
}
}
async onRoomClicked(room: OpenViduMeetRoom) {
async onRoomClicked(room: MeetRoom) {
console.log('Room clicked:', room);
//TODO: Go to room details page
await this.router.navigate([room.roomName, 'edit'], { relativeTo: this.route });

View File

@ -7,7 +7,7 @@ import { NgClass } from '@angular/common';
import { MatToolbar } from '@angular/material/toolbar';
import { Router } from '@angular/router';
import { AuthService, ContextService, HttpService } from '../../services/index';
import { OpenViduMeetRoom, OpenViduMeetRoomOptions } from '../../typings/ce/room';
import { MeetRoom, MeetRoomOptions } from '../../typings/ce/room';
import { animals, colors, Config, uniqueNamesGenerator } from 'unique-names-generator';
@Component({
@ -72,12 +72,12 @@ export class RoomCreatorComponent implements OnInit {
try {
// TODO: Fix expiration date
const options: OpenViduMeetRoomOptions = {
const options: MeetRoomOptions = {
roomNamePrefix,
expirationDate: Date.now() + 3600 * 1000 // 1 hour
};
const room: OpenViduMeetRoom = await this.httpService.createRoom(options);
const room: MeetRoom = await this.httpService.createRoom(options);
const accessRoomUrl = new URL(room.moderatorRoomUrl);
const secret = accessRoomUrl.searchParams.get('secret');

View File

@ -1,6 +1,6 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { OpenViduMeetRoom, OpenViduMeetRoomOptions } from 'projects/shared-meet-components/src/lib/typings/ce/room';
import { MeetRoom, MeetRoomOptions } from 'projects/shared-meet-components/src/lib/typings/ce/room';
import {
GlobalPreferences,
ParticipantRole,
@ -23,7 +23,7 @@ export class HttpService {
constructor(protected http: HttpClient) {}
createRoom(options: OpenViduMeetRoomOptions): Promise<OpenViduMeetRoom> {
createRoom(options: MeetRoomOptions): Promise<MeetRoom> {
return this.postRequest(`${this.API_PATH_PREFIX}/${this.API_V1_VERSION}/rooms`, options);
}
@ -31,7 +31,7 @@ export class HttpService {
return this.deleteRequest(`${this.API_PATH_PREFIX}/${this.API_V1_VERSION}/rooms/${roomName}`);
}
listRooms(fields?: string): Promise<OpenViduMeetRoom[]> {
listRooms(fields?: string): Promise<MeetRoom[]> {
let path = `${this.API_PATH_PREFIX}/${this.API_V1_VERSION}/rooms/`;
if (fields) {
path += `?fields=${encodeURIComponent(fields)}`;
@ -39,7 +39,7 @@ export class HttpService {
return this.getRequest(path);
}
getRoom(roomName: string, fields?: string): Promise<OpenViduMeetRoom> {
getRoom(roomName: string, fields?: string): Promise<MeetRoom> {
let path = `${this.API_PATH_PREFIX}/${this.API_V1_VERSION}/rooms/${roomName}`;
if (fields) {
path += `?fields=${encodeURIComponent(fields)}`;

View File

@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { RoomPreferences } from '@lib/typings/ce';
import { LoggerService } from 'openvidu-components-angular';
import { HttpService } from '../http/http.service';
import { OpenViduMeetRoom, OpenViduMeetRoomOptions } from 'projects/shared-meet-components/src/lib/typings/ce/room';
import { MeetRoom, MeetRoomOptions } from 'projects/shared-meet-components/src/lib/typings/ce/room';
@Injectable({
providedIn: 'root'
@ -17,9 +17,9 @@ export class RoomService {
this.log = this.loggerService.get('OpenVidu Meet - RoomService');
}
async createRoom(): Promise<OpenViduMeetRoom> {
async createRoom(): Promise<MeetRoom> {
// TODO: Improve expiration date
const options: OpenViduMeetRoomOptions = {
const options: MeetRoomOptions = {
roomNamePrefix: 'TestRoom-',
expirationDate: Date.now() + 1000 * 60 * 60 // 1 hour from now
};

View File

@ -9,12 +9,12 @@ interface BaseRoomOptions {
/**
* Options for creating or configuring a room.
*/
export type OpenViduMeetRoomOptions = BaseRoomOptions;
export type MeetRoomOptions = BaseRoomOptions;
/**
* Interface representing the response received when a room is created.
*/
export interface OpenViduMeetRoom extends BaseRoomOptions {
export interface MeetRoom extends BaseRoomOptions {
roomName: string;
creationDate: number;
moderatorRoomUrl: string;

View File

@ -1,7 +1,7 @@
import { MeetRecordingInfo } from './recording.model.js';
import { OpenViduMeetRoom } from './room.js';
import { MeetRoom } from './room.js';
export type MeetWebhookPayload = MeetRecordingInfo | OpenViduMeetRoom;
export type MeetWebhookPayload = MeetRecordingInfo | MeetRoom;
export const enum MeetWebhookEventType {
RECORDING_STARTED = 'recordingStarted',