add livekit webhooks

This commit is contained in:
Sergey Krylov 2025-07-13 09:53:02 +03:00
parent bffe2056b1
commit 79f9e5bb24
8 changed files with 96 additions and 6 deletions

View File

@ -55,6 +55,7 @@
"otpauth": "^9.4.0",
"prisma": "^6.10.1",
"qrcode": "^1.5.4",
"raw-body": "^3.0.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"reflect-metadata": "^0.2.2",

View File

@ -1,5 +1,5 @@
import { getGraphQLConfig } from '@/src/core/config/graphql.config'
import { getLiveKitConfig } from '@/src/core/config/livekit.config';
import { getLiveKitConfig } from '@/src/core/config/livekit.config'
import { AccountModule } from '@/src/module/auth/account/account.module'
import { DeactivateModule } from '@/src/module/auth/deactivate/deactivate.module'
import { PasswordRecoveryModule } from '@/src/module/auth/password-recovery/password-recovery.module'
@ -11,8 +11,9 @@ import { CronModule } from '@/src/module/cron/cron.module'
import { LiveKitModule } from '@/src/module/libs/livekit/livekit.module'
import { MailModule } from '@/src/module/libs/mail/mail.module'
import { StorageModule } from '@/src/module/libs/storage/storage.module'
import { IngressModule } from '@/src/module/stream/ingress/ingress.module';
import { IngressModule } from '@/src/module/stream/ingress/ingress.module'
import { StreamModule } from '@/src/module/stream/stream.module'
import { WebhookModule } from '@/src/module/webhook/webhook.module'
import { IS_DEV } from '@/src/shared/util/is-dev.util'
import { ApolloDriver } from '@nestjs/apollo'
import { Module } from '@nestjs/common'
@ -52,6 +53,7 @@ import { RedisModule } from './redis/redis.module'
ProfileModule,
StreamModule,
IngressModule,
WebhookModule,
],
})
export class CoreModule {}

View File

@ -8,7 +8,7 @@ import RedisStore from 'connect-redis'
import * as cookieParser from 'cookie-parser'
import { CoreModule } from '@/src/core/core.module'
import * as session from 'express-session'
import * as graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.js';
import * as graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.js'
async function bootstrap() {
const app = await NestFactory.create(CoreModule)

View File

@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { IngressService } from './ingress.service';
import { IngressResolver } from './ingress.resolver';
import { Module } from '@nestjs/common'
import { IngressService } from './ingress.service'
import { IngressResolver } from './ingress.resolver'
@Module({
providers: [IngressResolver, IngressService],

View File

@ -0,0 +1,20 @@
import { Controller, HttpCode, HttpStatus, Post, UnauthorizedException, Headers, Body } from '@nestjs/common'
import { WebhookService } from './webhook.service'
@Controller('webhook')
export class WebhookController {
constructor(private readonly webhookService: WebhookService) {}
@Post('livekit')
@HttpCode(HttpStatus.OK)
public receiveWebhookLiveKit(
@Body() body: string,
@Headers('Authorization') authorization: string,
) {
if (!authorization) {
throw new UnauthorizedException('Отстутсвует авторизация')
}
return this.webhookService.receiveWebhookLiveKit(body, authorization)
}
}

View File

@ -0,0 +1,16 @@
import { RawBodyMiddleware } from '@/src/shared/middlewares/raw-body.middleware'
import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common'
import { WebhookController } from './webhook.controller'
import { WebhookService } from './webhook.service'
@Module({
controllers: [WebhookController],
providers: [WebhookService],
})
export class WebhookModule {
public configure(consumer: MiddlewareConsumer) {
consumer
.apply(RawBodyMiddleware)
.forRoutes({ path: 'webhook/livekit', method: RequestMethod.POST })
}
}

View File

@ -0,0 +1,30 @@
import { PrismaService } from '@/src/core/prisma/prisma.service'
import { LiveKitService } from '@/src/module/libs/livekit/livekit.service'
import { Injectable } from '@nestjs/common'
@Injectable()
export class WebhookService {
constructor(
private prismaService: PrismaService,
private liveKitService: LiveKitService,
) {
}
public async receiveWebhookLiveKit(body: string, authorization: string) {
const event = this.liveKitService.webhook.receive(body, authorization, true)
if (event.event === 'ingress_started' && event.ingressInfo?.ingressId) {
await this.prismaService.stream.update({
where: { ingressId: event.ingressInfo.ingressId },
data: { isLive: true },
})
}
if (event.event === 'ingress_ended' && event.ingressInfo?.ingressId) {
await this.prismaService.stream.update({
where: { ingressId: event.ingressInfo.ingressId },
data: { isLive: false },
})
}
}
}

View File

@ -0,0 +1,21 @@
import { BadRequestException, Injectable, NestMiddleware } from '@nestjs/common'
import { NextFunction, Request, Response } from 'express'
import * as getRawBody from 'raw-body'
@Injectable()
export class RawBodyMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
if (!req.readable) {
return next(new BadRequestException('Неправильный запрос'))
}
getRawBody(req, { encoding: 'utf-8' })
.then((rawBody) => {
req.body = rawBody
next()
})
.catch((error: string) => {
throw new BadRequestException('Ошибка при получении', error)
})
}
}