WebRtc модуль и документация, импорт телеграма

This commit is contained in:
Халимов Рустам
2026-03-27 01:44:05 +03:00
parent b399649cfd
commit 16978c423c
11 changed files with 448 additions and 511 deletions
@@ -1,12 +1,11 @@
using Knot.Shared.Kernel;
using Knot.Shared.Kernel.Configuration;
using Microsoft.Extensions.Configuration;
using MediatR;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Host.Application.WebRtc.Queries;
namespace Knot.Modules.WebRtc.Application.WebRtc.Queries;
public record IceServerDto(string[] Urls, string? Username = null, string? Credential = null);
public record IceServersResultDto(List<IceServerDto> IceServers);
@@ -15,59 +14,52 @@ public record GetIceServersQuery : IQuery<IceServersResultDto>;
internal sealed class GetIceServersQueryHandler : IQueryHandler<GetIceServersQuery, IceServersResultDto>
{
private readonly IConfiguration _configuration;
private readonly IWebRtcSettings _settingsService;
private readonly ISettingsService _settingsService;
public GetIceServersQueryHandler(IConfiguration configuration, IWebRtcSettings settingsService)
public GetIceServersQueryHandler(ISettingsService settingsService)
{
_configuration = configuration;
_settingsService = settingsService;
}
public Task<Result<IceServersResultDto>> Handle(GetIceServersQuery request, CancellationToken cancellationToken)
public async Task<Result<IceServersResultDto>> Handle(GetIceServersQuery request, CancellationToken cancellationToken)
{
var settings = _settingsService.Current;
if (!settings.Enabled)
var settings = await _settingsService.GetSettingsAsync(cancellationToken);
var webrtc = settings.WebRtc;
if (!webrtc.Enabled)
{
return Task.FromResult(Result.Failure<IceServersResultDto>(new Error(
Knot.Shared.Kernel.Constants.Errors.DisabledByAdmin,
"Сервис отключен администратором."
)));
return Result.Failure<IceServersResultDto>(new Error(
"WebRtc.Disabled",
"WebRTC calls are disabled by the server administrator."));
}
var turnUrl = !string.IsNullOrEmpty(settings.TurnHost)
? $"turn:{settings.TurnHost}:{settings.TurnPort}"
: _configuration["WebRtc:TurnUrl"];
var turnUsername = !string.IsNullOrEmpty(settings.TurnUser)
? settings.TurnUser
: _configuration["WebRtc:TurnUsername"];
var turnSecret = !string.IsNullOrEmpty(settings.TurnSecret)
? settings.TurnSecret
: _configuration["WebRtc:TurnPassword"];
var iceServers = new List<IceServerDto>();
if (!string.IsNullOrEmpty(turnUrl))
// Если хост TURN задан, формируем STUN и TURN записи
if (!string.IsNullOrEmpty(webrtc.TurnHost))
{
var stunUrl = turnUrl.Replace("turn:", "stun:");
iceServers.Add(new IceServerDto(new[] { stunUrl }));
var turnUrl = $"turn:{webrtc.TurnHost}:{webrtc.TurnPort}";
var stunUrl = $"stun:{webrtc.TurnHost}:{webrtc.TurnPort}";
if (!string.IsNullOrEmpty(turnUsername))
// Всегда добавляем STUN (публичный или свой)
iceServers.Add(new IceServerDto(new[] { stunUrl, "stun:stun.l.google.com:19302" }));
// Добавляем TURN (TCP и UDP варианты)
if (!string.IsNullOrEmpty(webrtc.TurnUser))
{
iceServers.Add(new IceServerDto(
new[] { turnUrl, turnUrl + "?transport=tcp" },
turnUsername,
!string.IsNullOrEmpty(turnSecret) ? turnSecret : turnUsername
new[] { turnUrl, $"{turnUrl}?transport=tcp" },
webrtc.TurnUser,
!string.IsNullOrEmpty(webrtc.TurnSecret) ? webrtc.TurnSecret : webrtc.TurnUser
));
}
else
{
iceServers.Add(new IceServerDto(new[] { turnUrl, turnUrl + "?transport=tcp" }));
}
}
else
{
// Если своего сервера нет, используем публичный Google STUN как fallback
iceServers.Add(new IceServerDto(new[] { "stun:stun.l.google.com:19302" }));
}
return Task.FromResult(Result.Success(new IceServersResultDto(iceServers)));
return Result.Success(new IceServersResultDto(iceServers));
}
}
@@ -1,25 +1,26 @@
using Carter;
using MediatR;
using Knot.Shared.Kernel;
using Knot.Modules.WebRtc.Application.WebRtc.Queries;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
namespace Host.Endpoints;
namespace Knot.Modules.WebRtc.Presentation.Endpoints;
/// <summary>
/// Регистрация эндпоинтов WebRTC
/// Endpoints for WebRTC signaling and ICE configuration
/// </summary>
public sealed class WebRtcEndpoints : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
var group = app.MapGroup(Knot.Shared.Kernel.Constants.Routes.ApiWebRtc)
var group = app.MapGroup("api/webrtc")
.RequireAuthorization();
group.MapGet("/ice-servers", async (ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(new Host.Application.WebRtc.Queries.GetIceServersQuery(), ct);
var result = await sender.Send(new GetIceServersQuery(), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
})
.WithName("GetIceServers")