backend: implement HttpContextService and middleware for managing HTTP context. Refactor base URL retrieval logic
This commit is contained in:
parent
8894174eb9
commit
43839fdb9d
@ -8,6 +8,7 @@ import {
|
|||||||
FrontendEventService,
|
FrontendEventService,
|
||||||
GCSService,
|
GCSService,
|
||||||
GCSStorageProvider,
|
GCSStorageProvider,
|
||||||
|
HttpContextService,
|
||||||
LiveKitService,
|
LiveKitService,
|
||||||
LivekitWebhookService,
|
LivekitWebhookService,
|
||||||
LoggerService,
|
LoggerService,
|
||||||
@ -52,6 +53,7 @@ export const registerDependencies = () => {
|
|||||||
container.bind(DistributedEventService).toSelf().inSingletonScope();
|
container.bind(DistributedEventService).toSelf().inSingletonScope();
|
||||||
container.bind(MutexService).toSelf().inSingletonScope();
|
container.bind(MutexService).toSelf().inSingletonScope();
|
||||||
container.bind(TaskSchedulerService).toSelf().inSingletonScope();
|
container.bind(TaskSchedulerService).toSelf().inSingletonScope();
|
||||||
|
container.bind(HttpContextService).toSelf().inSingletonScope();
|
||||||
|
|
||||||
configureStorage(MEET_BLOB_STORAGE_MODE);
|
configureStorage(MEET_BLOB_STORAGE_MODE);
|
||||||
container.bind(StorageFactory).toSelf().inSingletonScope();
|
container.bind(StorageFactory).toSelf().inSingletonScope();
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
rejectRequestFromMeetError
|
rejectRequestFromMeetError
|
||||||
} from '../models/error.model.js';
|
} from '../models/error.model.js';
|
||||||
import { AuthService, LoggerService, TokenService, UserService } from '../services/index.js';
|
import { AuthService, LoggerService, TokenService, UserService } from '../services/index.js';
|
||||||
import { getCookieOptions } from '../utils/cookie-utils.js';
|
import { getCookieOptions } from '../utils/index.js';
|
||||||
|
|
||||||
export const login = async (req: Request, res: Response) => {
|
export const login = async (req: Request, res: Response) => {
|
||||||
const logger = container.get(LoggerService);
|
const logger = container.get(LoggerService);
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
rejectRequestFromMeetError
|
rejectRequestFromMeetError
|
||||||
} from '../models/error.model.js';
|
} from '../models/error.model.js';
|
||||||
import { LoggerService, ParticipantService, RoomService, TokenService } from '../services/index.js';
|
import { LoggerService, ParticipantService, RoomService, TokenService } from '../services/index.js';
|
||||||
import { getCookieOptions } from '../utils/cookie-utils.js';
|
import { getCookieOptions } from '../utils/index.js';
|
||||||
|
|
||||||
export const generateParticipantToken = async (req: Request, res: Response) => {
|
export const generateParticipantToken = async (req: Request, res: Response) => {
|
||||||
const logger = container.get(LoggerService);
|
const logger = container.get(LoggerService);
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { Request, Response } from 'express';
|
|||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
import { container } from '../config/index.js';
|
import { container } from '../config/index.js';
|
||||||
import INTERNAL_CONFIG from '../config/internal-config.js';
|
import INTERNAL_CONFIG from '../config/internal-config.js';
|
||||||
import { getBaseUrl } from '../environment.js';
|
|
||||||
import { RecordingHelper } from '../helpers/index.js';
|
import { RecordingHelper } from '../helpers/index.js';
|
||||||
import {
|
import {
|
||||||
errorRecordingNotFound,
|
errorRecordingNotFound,
|
||||||
@ -13,6 +12,7 @@ import {
|
|||||||
rejectRequestFromMeetError
|
rejectRequestFromMeetError
|
||||||
} from '../models/error.model.js';
|
} from '../models/error.model.js';
|
||||||
import { LoggerService, MeetStorageService, RecordingService } from '../services/index.js';
|
import { LoggerService, MeetStorageService, RecordingService } from '../services/index.js';
|
||||||
|
import { getBaseUrl } from '../utils/index.js';
|
||||||
|
|
||||||
export const startRecording = async (req: Request, res: Response) => {
|
export const startRecording = async (req: Request, res: Response) => {
|
||||||
const logger = container.get(LoggerService);
|
const logger = container.get(LoggerService);
|
||||||
@ -125,10 +125,7 @@ export const stopRecording = async (req: Request, res: Response) => {
|
|||||||
const recordingService = container.get(RecordingService);
|
const recordingService = container.get(RecordingService);
|
||||||
|
|
||||||
const recordingInfo = await recordingService.stopRecording(recordingId);
|
const recordingInfo = await recordingService.stopRecording(recordingId);
|
||||||
res.setHeader(
|
res.setHeader('Location', `${getBaseUrl()}${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${recordingId}`);
|
||||||
'Location',
|
|
||||||
`${getBaseUrl()}${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${recordingId}`
|
|
||||||
);
|
|
||||||
return res.status(202).json(recordingInfo);
|
return res.status(202).json(recordingInfo);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(res, error, `stopping recording '${recordingId}'`);
|
handleError(res, error, `stopping recording '${recordingId}'`);
|
||||||
|
|||||||
@ -10,10 +10,9 @@ import {
|
|||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { container } from '../config/index.js';
|
import { container } from '../config/index.js';
|
||||||
import INTERNAL_CONFIG from '../config/internal-config.js';
|
import INTERNAL_CONFIG from '../config/internal-config.js';
|
||||||
import { getBaseUrl } from '../environment.js';
|
|
||||||
import { handleError } from '../models/error.model.js';
|
import { handleError } from '../models/error.model.js';
|
||||||
import { LoggerService, ParticipantService, RoomService } from '../services/index.js';
|
import { LoggerService, ParticipantService, RoomService } from '../services/index.js';
|
||||||
import { getCookieOptions } from '../utils/cookie-utils.js';
|
import { getBaseUrl, getCookieOptions } from '../utils/index.js';
|
||||||
|
|
||||||
export const createRoom = async (req: Request, res: Response) => {
|
export const createRoom = async (req: Request, res: Response) => {
|
||||||
const logger = container.get(LoggerService);
|
const logger = container.get(LoggerService);
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export const {
|
|||||||
SERVER_CORS_ORIGIN = '*',
|
SERVER_CORS_ORIGIN = '*',
|
||||||
MEET_LOG_LEVEL = 'info',
|
MEET_LOG_LEVEL = 'info',
|
||||||
MEET_NAME_ID = 'openviduMeet',
|
MEET_NAME_ID = 'openviduMeet',
|
||||||
MEET_BASE_URL = `http://localhost:${SERVER_PORT}`,
|
MEET_BASE_URL = '',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authentication configuration
|
* Authentication configuration
|
||||||
@ -86,13 +86,6 @@ export const {
|
|||||||
ENABLED_MODULES = ''
|
ENABLED_MODULES = ''
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the base URL without trailing slash
|
|
||||||
*/
|
|
||||||
export const getBaseUrl = (): string => {
|
|
||||||
return MEET_BASE_URL.endsWith('/') ? MEET_BASE_URL.slice(0, -1) : MEET_BASE_URL;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function checkModuleEnabled() {
|
export function checkModuleEnabled() {
|
||||||
if (MODULES_FILE) {
|
if (MODULES_FILE) {
|
||||||
const moduleName = MODULE_NAME;
|
const moduleName = MODULE_NAME;
|
||||||
|
|||||||
15
backend/src/middlewares/http-context.middleware.ts
Normal file
15
backend/src/middlewares/http-context.middleware.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { NextFunction, Request, Response } from 'express';
|
||||||
|
import { container } from '../config/dependency-injector.config.js';
|
||||||
|
import { HttpContextService } from '../services/index.js';
|
||||||
|
|
||||||
|
export const httpContextMiddleware = (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const httpContextService = container.get(HttpContextService);
|
||||||
|
httpContextService.setContext(req);
|
||||||
|
|
||||||
|
// Clear context after response is finished
|
||||||
|
res.on('finish', () => {
|
||||||
|
httpContextService.clearContext();
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
@ -1,4 +1,5 @@
|
|||||||
export * from './content-type.middleware.js';
|
export * from './content-type.middleware.js';
|
||||||
|
export * from './http-context.middleware.js';
|
||||||
export * from './auth.middleware.js';
|
export * from './auth.middleware.js';
|
||||||
export * from './room.middleware.js';
|
export * from './room.middleware.js';
|
||||||
export * from './participant.middleware.js';
|
export * from './participant.middleware.js';
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import express, { Express, Request, Response } from 'express';
|
|||||||
import { initializeEagerServices, registerDependencies } from './config/index.js';
|
import { initializeEagerServices, registerDependencies } from './config/index.js';
|
||||||
import INTERNAL_CONFIG from './config/internal-config.js';
|
import INTERNAL_CONFIG from './config/internal-config.js';
|
||||||
import { SERVER_CORS_ORIGIN, SERVER_PORT, logEnvVars } from './environment.js';
|
import { SERVER_CORS_ORIGIN, SERVER_PORT, logEnvVars } from './environment.js';
|
||||||
import { jsonSyntaxErrorHandler } from './middlewares/index.js';
|
import { httpContextMiddleware, jsonSyntaxErrorHandler } from './middlewares/index.js';
|
||||||
import {
|
import {
|
||||||
authRouter,
|
authRouter,
|
||||||
configRouter,
|
configRouter,
|
||||||
@ -24,7 +24,7 @@ import {
|
|||||||
internalApiHtmlFilePath,
|
internalApiHtmlFilePath,
|
||||||
publicApiHtmlFilePath,
|
publicApiHtmlFilePath,
|
||||||
webcomponentBundlePath
|
webcomponentBundlePath
|
||||||
} from './utils/path-utils.js';
|
} from './utils/path.utils.js';
|
||||||
|
|
||||||
const createApp = () => {
|
const createApp = () => {
|
||||||
const app: Express = express();
|
const app: Express = express();
|
||||||
@ -41,10 +41,14 @@ const createApp = () => {
|
|||||||
|
|
||||||
// Serve static files
|
// Serve static files
|
||||||
app.use(express.static(frontendDirectoryPath));
|
app.use(express.static(frontendDirectoryPath));
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(jsonSyntaxErrorHandler);
|
app.use(jsonSyntaxErrorHandler);
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
|
|
||||||
|
// Middleware to set HTTP context
|
||||||
|
app.use(httpContextMiddleware);
|
||||||
|
|
||||||
// Public API routes
|
// Public API routes
|
||||||
app.use(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/docs`, (_req: Request, res: Response) =>
|
app.use(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/docs`, (_req: Request, res: Response) =>
|
||||||
res.sendFile(publicApiHtmlFilePath)
|
res.sendFile(publicApiHtmlFilePath)
|
||||||
|
|||||||
39
backend/src/services/http-context.service.ts
Normal file
39
backend/src/services/http-context.service.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { Request } from 'express';
|
||||||
|
import { injectable } from 'inversify';
|
||||||
|
import { SERVER_PORT } from '../environment.js';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class HttpContextService {
|
||||||
|
private baseUrl: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.baseUrl = this.getDefaultBaseUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current HTTP context from the request
|
||||||
|
*/
|
||||||
|
setContext(req: Request): void {
|
||||||
|
const protocol = req.protocol;
|
||||||
|
const host = req.get('host');
|
||||||
|
this.baseUrl = `${protocol}://${host}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the base URL from the current context
|
||||||
|
*/
|
||||||
|
getBaseUrl(): string {
|
||||||
|
return this.baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the current context
|
||||||
|
*/
|
||||||
|
clearContext(): void {
|
||||||
|
this.baseUrl = this.getDefaultBaseUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDefaultBaseUrl(): string {
|
||||||
|
return `http://localhost:${SERVER_PORT}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ export * from './redis.service.js';
|
|||||||
export * from './distributed-event.service.js';
|
export * from './distributed-event.service.js';
|
||||||
export * from './mutex.service.js';
|
export * from './mutex.service.js';
|
||||||
export * from './task-scheduler.service.js';
|
export * from './task-scheduler.service.js';
|
||||||
|
export * from './http-context.service.js';
|
||||||
|
|
||||||
export * from './storage/index.js';
|
export * from './storage/index.js';
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import {
|
|||||||
internalError,
|
internalError,
|
||||||
OpenViduMeetError
|
OpenViduMeetError
|
||||||
} from '../models/error.model.js';
|
} from '../models/error.model.js';
|
||||||
import { chunkArray } from '../utils/array.utils.js';
|
import { chunkArray } from '../utils/index.js';
|
||||||
import { LoggerService } from './index.js';
|
import { LoggerService } from './index.js';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { inject, injectable } from 'inversify';
|
|||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
import {
|
import {
|
||||||
getBaseUrl,
|
|
||||||
MEET_INITIAL_ADMIN_PASSWORD,
|
MEET_INITIAL_ADMIN_PASSWORD,
|
||||||
MEET_INITIAL_ADMIN_USER,
|
MEET_INITIAL_ADMIN_USER,
|
||||||
MEET_INITIAL_API_KEY,
|
MEET_INITIAL_API_KEY,
|
||||||
@ -20,6 +19,7 @@ import {
|
|||||||
OpenViduMeetError,
|
OpenViduMeetError,
|
||||||
RedisKeyName
|
RedisKeyName
|
||||||
} from '../../models/index.js';
|
} from '../../models/index.js';
|
||||||
|
import { getBaseUrl } from '../../utils/index.js';
|
||||||
import { LoggerService, MutexService, RedisService } from '../index.js';
|
import { LoggerService, MutexService, RedisService } from '../index.js';
|
||||||
import { StorageFactory } from './storage.factory.js';
|
import { StorageFactory } from './storage.factory.js';
|
||||||
import { StorageKeyBuilder, StorageProvider } from './storage.interface.js';
|
import { StorageKeyBuilder, StorageProvider } from './storage.interface.js';
|
||||||
|
|||||||
3
backend/src/utils/index.ts
Normal file
3
backend/src/utils/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './array.utils.js';
|
||||||
|
export * from './cookie.utils.js';
|
||||||
|
export * from './url.utils.js';
|
||||||
21
backend/src/utils/url.utils.ts
Normal file
21
backend/src/utils/url.utils.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { container } from '../config/dependency-injector.config.js';
|
||||||
|
import { MEET_BASE_URL } from '../environment.js';
|
||||||
|
import { HttpContextService } from '../services/http-context.service.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base URL for the application.
|
||||||
|
*
|
||||||
|
* If the global `MEET_BASE_URL` variable is defined, it returns its value,
|
||||||
|
* ensuring there is no trailing slash. Otherwise, it retrieves the base URL
|
||||||
|
* from the `HttpContextService` instance.
|
||||||
|
*
|
||||||
|
* @returns {string} The base URL as a string.
|
||||||
|
*/
|
||||||
|
export const getBaseUrl = (): string => {
|
||||||
|
if (MEET_BASE_URL) {
|
||||||
|
return MEET_BASE_URL.endsWith('/') ? MEET_BASE_URL.slice(0, -1) : MEET_BASE_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const httpContextService = container.get(HttpContextService);
|
||||||
|
return httpContextService.getBaseUrl();
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user