backend: Add refresh participant token endpoint and refactor token generation logic

This commit is contained in:
juancarmore 2025-03-14 01:36:51 +01:00
parent cf1c4c5438
commit c72315d90a
5 changed files with 47 additions and 32 deletions

View File

@ -4,34 +4,20 @@ import { LoggerService } from '../services/logger.service.js';
import { TokenOptions } from '@typings-ce';
import { OpenViduMeetError } from '../models/index.js';
import { ParticipantService } from '../services/participant.service.js';
import { RoomService } from '../services/room.service.js';
import { MEET_PARTICIPANT_TOKEN_EXPIRATION, PARTICIPANT_TOKEN_COOKIE_NAME } from '../environment.js';
import { getCookieOptions } from '../utils/cookie-utils.js';
export const generateParticipantToken = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const tokenOptions: TokenOptions = req.body;
const { roomName, secret, participantName } = tokenOptions;
const { roomName } = tokenOptions;
const participantService = container.get(ParticipantService);
try {
const roomService = container.get(RoomService);
const participantService = container.get(ParticipantService);
// Check if participant with same participantName exists in the room
const participantExists = await participantService.participantExists(roomName, participantName);
if (participantExists) {
logger.verbose(`Participant ${participantName} already exists in room ${roomName}`);
return res.status(409).json({ message: 'Participant already exists' });
}
logger.verbose(`Generating participant token for room ${roomName}`);
const secretRole = await roomService.getRoomSecretRole(roomName, secret);
const token = await participantService.generateParticipantToken(secretRole, tokenOptions);
const token = await participantService.generateOrRefreshParticipantToken(tokenOptions);
res.cookie(PARTICIPANT_TOKEN_COOKIE_NAME, token, getCookieOptions('/', MEET_PARTICIPANT_TOKEN_EXPIRATION));
logger.verbose(`Participant token generated for room ${roomName}`);
return res.status(200).json({ token });
} catch (error) {
@ -40,6 +26,25 @@ export const generateParticipantToken = async (req: Request, res: Response) => {
}
};
export const refreshParticipantToken = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const tokenOptions: TokenOptions = req.body;
const { roomName } = tokenOptions;
const participantService = container.get(ParticipantService);
try {
logger.verbose(`Refreshing participant token for room ${roomName}`);
const token = await participantService.generateOrRefreshParticipantToken(tokenOptions, true);
res.cookie(PARTICIPANT_TOKEN_COOKIE_NAME, token, getCookieOptions('/', MEET_PARTICIPANT_TOKEN_EXPIRATION));
logger.verbose(`Participant token refreshed for room ${roomName}`);
return res.status(200).json({ token });
} catch (error) {
logger.error(`Error refreshing participant token for room: ${roomName}`);
return handleError(res, error);
}
};
export const deleteParticipant = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const participantService = container.get(ParticipantService);

View File

@ -11,6 +11,7 @@ participantsInternalRouter.use(bodyParser.urlencoded({ extended: true }));
participantsInternalRouter.use(bodyParser.json());
participantsInternalRouter.post('/token', validateParticipantTokenRequest, participantCtrl.generateParticipantToken);
participantsInternalRouter.post('/token/refresh', validateParticipantTokenRequest, participantCtrl.refreshParticipantToken);
export const participantsRouter = Router();
participantsRouter.use(bodyParser.urlencoded({ extended: true }));

View File

@ -24,7 +24,6 @@ import {
import { LoggerService } from './logger.service.js';
import {
errorLivekitIsNotAvailable,
errorParticipantAlreadyExists,
errorParticipantNotFound,
errorRoomNotFound,
internalError
@ -132,17 +131,6 @@ export class LiveKitService {
role: ParticipantRole
): Promise<string> {
const { roomName, participantName } = options;
try {
if (await this.participantExists(roomName, participantName)) {
this.logger.error(`Participant ${participantName} already exists in room ${roomName}`);
throw errorParticipantAlreadyExists(participantName, roomName);
}
} catch (error) {
this.logger.error(`Error checking participant existence, ${JSON.stringify(error)}`);
throw error;
}
this.logger.info(`Generating token for ${participantName} in room ${roomName}`);
const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, {

View File

@ -3,17 +3,39 @@ import { LiveKitService } from './livekit.service.js';
import { LoggerService } from './logger.service.js';
import { ParticipantPermissions, ParticipantRole, TokenOptions } from '@typings-ce';
import { ParticipantInfo } from 'livekit-server-sdk';
import { RoomService } from './room.service.js';
import { errorParticipantAlreadyExists, errorParticipantNotFound } from '../models/index.js';
@injectable()
export class ParticipantService {
constructor(
@inject(LoggerService) protected logger: LoggerService,
@inject(RoomService) protected roomService: RoomService,
@inject(LiveKitService) protected livekitService: LiveKitService
) {}
async generateParticipantToken(role: ParticipantRole, options: TokenOptions): Promise<string> {
const permissions = this.getParticipantPermissions(role, options.roomName);
async generateOrRefreshParticipantToken(options: TokenOptions, refresh = false): Promise<string> {
const { roomName, participantName, secret } = options;
// Check if participant with same participantName exists in the room
const participantExists = await this.participantExists(roomName, participantName);
if (!refresh && participantExists) {
this.logger.verbose(`Participant ${participantName} already exists in room ${roomName}`);
throw errorParticipantAlreadyExists(participantName, roomName);
}
if (refresh && !participantExists) {
this.logger.verbose(`Participant ${participantName} does not exist in room ${roomName}`);
throw errorParticipantNotFound(participantName, roomName);
}
const role = await this.roomService.getRoomSecretRole(roomName, secret);
return this.generateParticipantToken(role, options);
}
protected async generateParticipantToken(role: ParticipantRole, options: TokenOptions): Promise<string> {
const permissions = this.getParticipantPermissions(role, options.roomName);
return this.livekitService.generateToken(options, permissions, role);
}

View File

@ -23,7 +23,6 @@ export class RoomService {
@inject(LoggerService) protected logger: LoggerService,
@inject(GlobalPreferencesService) protected globalPrefService: GlobalPreferencesService,
@inject(LiveKitService) protected livekitService: LiveKitService,
@inject(ParticipantService) protected participantService: ParticipantService,
@inject(SystemEventService) protected systemEventService: SystemEventService,
@inject(TaskSchedulerService) protected taskSchedulerService: TaskSchedulerService
) {}