WGShare.API/WGShare.API/Controllers/Frontend/AgoraCallbackController.cs

201 lines
6.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AgoraIO.Media;
using AgoraIO.Rtm;
using Mapster;
using Masuit.Tools;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using SharpCompress;
using SqlSugar;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using WGShare.API.Controllers.Basic;
using WGShare.API.Helpers;
using WGShare.Domain.AgoraApiResult;
using WGShare.Domain.Constant;
using WGShare.Domain.DTOs.AgoraCallback;
using WGShare.Domain.DTOs.Room;
using WGShare.Domain.Entities;
using WGShare.Domain.FriendlyException;
using WGShare.Domain.GeneralModel;
using Yitter.IdGenerator;
namespace WGShare.API.Controllers.Frontend
{
/// <summary>
/// Agora接口
/// </summary>
[ApiExplorerSettings(GroupName = "frontend")]
[Route("agora-cb"), AllowAnonymous]
public class AgoraCallbackController : BasicController
{
private readonly ILogger<AgoraCallbackController> _logger;
private readonly AgoraHelper _agoraHelper;
private readonly IConfiguration _configuration;
private readonly ISqlSugarClient _sqlSugarClient;
private readonly IHostEnvironment _hostEnvironment;
public AgoraCallbackController(
ILogger<AgoraCallbackController> logger,
AgoraHelper agoraHelper,
IConfiguration configuration,
ISqlSugarClient sqlSugarClient,
IHostEnvironment hostEnvironment)
{
this._logger = logger;
this._agoraHelper = agoraHelper;
this._configuration = configuration;
this._sqlSugarClient = sqlSugarClient;
this._hostEnvironment = hostEnvironment;
}
[HttpPost("event")]
public async Task Event()
{
using var reader = new StreamReader(Request.Body);
var bodyString = await reader.ReadToEndAsync();
//_logger.LogInformation($"Agora回调内容{bodyString}");
// 校验请求体是否为空
if (string.IsNullOrWhiteSpace(bodyString))
{
await ExceptionNotice.SendAsync(new ArgumentNullException("Agora-Signature-V2 声网请求体为空"), "声网回调异常");
return;
}
var body = bodyString.FromJson<EventBody>();
if (body == null)
{
await ExceptionNotice.SendAsync(new InvalidDataException("Agora-Signature-V2 声网请求体反序列化失败"), "声网回调异常");
return;
}
// 声网健康检查回调,直接返回
if (body.payload.channelName == "test_webhook")
{
_logger.LogDebug($"测试回调,测试信息:{bodyString}");
return;
}
// 验证签名
var sig = Request.Headers["Agora-Signature-V2"].ToString();
if (!await _agoraHelper.CheckSignatureAsync(sig, bodyString))
{
_logger.LogWarning($"Agora回调签名验证失败声网签名{sig}");
return;
}
switch (body.eventType)
{
case Domain.Enums.EventType.channel_create:
await CreateChannel(body);
break;
case Domain.Enums.EventType.channel_destroy:
await DestroyChannel(body);
break;
case Domain.Enums.EventType.broadcaster_join_channel:
case Domain.Enums.EventType.audience_join_channel:
JoinChannelEvent(bodyString, body);
break;
case Domain.Enums.EventType.broadcaster_leave_channel:
case Domain.Enums.EventType.audience_leave_channel:
LeaveChannelEvent(bodyString);
break;
case Domain.Enums.EventType.client_role_change_to_broadcaster:
break;
case Domain.Enums.EventType.client_role_change__to_audience:
break;
default:
await ExceptionNotice.SendAsync(new Exception("声网事件未知类型"), "声网回调异常");
break;
}
}
/// <summary>
/// 加入频道
/// </summary>
[NonAction]
private void JoinChannelEvent(string bodyString, EventBody eventBody)
{
_logger.LogDebug($"Agora回调内容 加入频道:{bodyString}");
RedisHelper.Instance.LPush(RedisKeyConstant.PubSub.MeetingRecord, bodyString);
}
/// <summary>
/// 离开频道
/// </summary>
[NonAction]
private void LeaveChannelEvent(string bodyString)
{
_logger.LogDebug($"Agora回调内容 离开频道:{bodyString}");
// 离会记录
RedisHelper.Instance.LPush(RedisKeyConstant.PubSub.MeetingRecord, bodyString);
}
static List<string> excludeChannel = new();
static ConcurrentDictionary<string, int> existsChannel = new();
/// <summary>
/// 创建频道
/// </summary>
[NonAction]
private async Task CreateChannel(EventBody eventBody)
{
if (_hostEnvironment.IsDevelopment())
{
_logger.LogDebug($"测试环境不通知创建频道");
return;
}
if (excludeChannel.IsNullOrEmpty())
{
// 缓存测试区域房间
excludeChannel = await _sqlSugarClient.Queryable<Room>().Where(x => x.TenantId == "559167236182085")
.Select(x => x.RoomNum).ToListAsync();
}
if (excludeChannel.Any(x => x == eventBody.payload.channelName))
{
_logger.LogDebug($"正式环境的测试区域不通知创建频道");
return;
}
if (existsChannel.TryAdd(eventBody.payload.channelName, 0))
{
var roomInfo = await _sqlSugarClient.Queryable<Room>()
.LeftJoin<Tenant>((r, t) => r.TenantId == t.Id)
.Where((r, t) => r.RoomNum == eventBody.payload.channelName)
.Select((r, t) => new Room
{
Id = r.Id.SelectAll(),
TenantName = t.TenantName
})
.FirstAsync();
ExceptionNotice.JoinAsync(eventBody, roomInfo);
}
}
/// <summary>
/// 销毁频道
/// </summary>
[NonAction]
private async Task DestroyChannel(EventBody eventBody)
{
if (_hostEnvironment.IsDevelopment())
return;
existsChannel.TryRemove(eventBody.payload.channelName, out _);
}
}
}