434 lines
16 KiB
C#
434 lines
16 KiB
C#
using AgoraIO.Media;
|
||
using Hangfire.MemoryStorage.Database;
|
||
using Mapster;
|
||
using Masuit.Tools;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.AspNetCore.SignalR;
|
||
using Microsoft.IdentityModel.Tokens;
|
||
using SqlSugar;
|
||
using SqlSugar.Extensions;
|
||
using WGShare.API.Controllers.Basic;
|
||
using WGShare.API.Helpers;
|
||
using WGShare.API.Hubs;
|
||
using WGShare.Domain.Constant;
|
||
using WGShare.Domain.DTOs.File;
|
||
using WGShare.Domain.DTOs.Room;
|
||
using WGShare.Domain.DTOs.User;
|
||
using WGShare.Domain.Entities;
|
||
using WGShare.Domain.FriendlyException;
|
||
using WGShare.Domain.GeneralModel;
|
||
using Yitter.IdGenerator;
|
||
|
||
namespace WGShare.API.Controllers.Frontend
|
||
{
|
||
/// <summary>
|
||
/// 会议室接口
|
||
/// </summary>
|
||
[ApiExplorerSettings(GroupName = "frontend")]
|
||
[Route("room")]
|
||
public class RoomController : BasicController
|
||
{
|
||
private readonly ISqlSugarClient _sqlSugar;
|
||
private readonly IConfiguration _configuration;
|
||
private readonly OssHelper _ossHelper;
|
||
private readonly AgoraHelper _agoraHelper;
|
||
private readonly IHubContext<SessionManageHub, IMessageClient> _hubContext;
|
||
private readonly ILogger<RoomController> _logger;
|
||
|
||
public RoomController(ISqlSugarClient sqlSugar,
|
||
IConfiguration configuration,
|
||
OssHelper ossHelper,
|
||
AgoraHelper agoraHelper,
|
||
IHubContext<SessionManageHub, IMessageClient> hubContext,
|
||
ILogger<RoomController> logger)
|
||
{
|
||
this._sqlSugar = sqlSugar;
|
||
this._configuration = configuration;
|
||
this._ossHelper = ossHelper;
|
||
this._agoraHelper = agoraHelper;
|
||
this._hubContext = hubContext;
|
||
this._logger = logger;
|
||
}
|
||
|
||
///// <summary>
|
||
///// 获取会议室管理员
|
||
///// </summary>
|
||
///// <returns></returns>
|
||
//[HttpGet("manager")]
|
||
//public async Task<List<string>> GetRoomManager([FromQuery] string roomId)
|
||
//{
|
||
// return await _sqlSugar.Queryable<RoomManager>()
|
||
// .Where(x => x.RoomId == roomId)
|
||
// .Select(x => x.UserId)
|
||
// .ToListAsync();
|
||
//}
|
||
|
||
/// <summary>
|
||
/// 设置房间管理员
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpPost("manager")]
|
||
public async Task<bool> SetRoomManager([FromQuery] string roomId, [FromBody] List<string> userIds)
|
||
{
|
||
var entities = userIds.ConvertAll(x => new RoomManager
|
||
{
|
||
RoomId = roomId,
|
||
UserId = x
|
||
});
|
||
|
||
return await _sqlSugar.Insertable(entities).ExecuteCommandAsync() > 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取消房间管理员
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpDelete("manager")]
|
||
public async Task<bool> DelRoomManager([FromQuery] string roomId, [FromBody] List<string> userIds)
|
||
{
|
||
return await _sqlSugar.Deleteable<RoomManager>()
|
||
.Where(x => x.RoomId == roomId && userIds.Contains(x.UserId))
|
||
.ExecuteCommandAsync() > 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询用户信息
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("user")]
|
||
public async Task<List<UserOutputDTO>> GetUsers([FromQuery] string roomNum)
|
||
{
|
||
var channelUsers = RedisHelper.Instance.HVals<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
if (channelUsers.IsNullOrEmpty())
|
||
{
|
||
return new List<UserOutputDTO>();
|
||
}
|
||
|
||
var uids = channelUsers.Select(x => x.UID);
|
||
var users = await _sqlSugar.Queryable<User>()
|
||
.Where(x => uids.Contains(x.Id))
|
||
.ToListAsync();
|
||
|
||
var managerIds = await _sqlSugar.Queryable<RoomManager>()
|
||
.InnerJoin<Room>((rm, r) => r.Id == rm.RoomId)
|
||
.Where((rm, r) => r.RoomNum == roomNum)
|
||
.Select((rm, r) => rm.UserId)
|
||
.ToListAsync();
|
||
|
||
var result = users.Adapt<List<UserOutputDTO>>();
|
||
|
||
result.ForEach(x =>
|
||
{
|
||
x.IsManager = (x.RoleId == "1" || managerIds.Contains(x.Id));
|
||
var info = channelUsers.FirstOrDefault(q => q.UID == x.Id);
|
||
if (info != null)
|
||
{
|
||
x.EnableMicr = info.EnableMicr;
|
||
x.EnableCamera = info.EnableCamera;
|
||
}
|
||
});
|
||
|
||
return result;
|
||
|
||
|
||
|
||
#region 暂时不用声网获取用户列表
|
||
|
||
//var data = await _agoraHelper.GetChannelUserList(roomNum);
|
||
//if (data == null)
|
||
//{
|
||
// throw Oops.Oh("请求失败");
|
||
//}
|
||
//if (!data.channel_exist)
|
||
//{
|
||
// throw Oops.Oh("频道不存在");
|
||
//}
|
||
//if (data.broadcasters.IsNullOrEmpty())
|
||
//{
|
||
// return new List<UserOutputDTO>();
|
||
//}
|
||
//var accounts = data.broadcasters.ConvertAll(x => x.ToString());
|
||
|
||
//var users = await _sqlSugar.Queryable<User>()
|
||
// .Where(x => accounts.Contains(x.Account))
|
||
// .ToListAsync();
|
||
|
||
//var managerIds = await _sqlSugar.Queryable<RoomManager>()
|
||
// .InnerJoin<Room>((rm, r) => r.Id == rm.RoomId)
|
||
// .Where((rm, r) => r.RoomNum == roomNum)
|
||
// .Select((rm, r) => rm.UserId)
|
||
// .ToListAsync();
|
||
|
||
|
||
//var result = users.Adapt<List<UserOutputDTO>>();
|
||
|
||
//result.ForEach(x => x.IsManager = managerIds.Contains(x.Id));
|
||
|
||
//return result;
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检验房间是否存在
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("checkout"), AllowAnonymous]
|
||
public async Task<bool> ExistsRoom([FromQuery] string roomNum)
|
||
{
|
||
return await _sqlSugar.Queryable<Room>().AnyAsync(x => x.RoomNum == roomNum && x.IsDelete == false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取单个会议室信息
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("{roomNum}")]
|
||
public async Task<RoomOutputDTO> GetRoom([FromRoute] string roomNum)
|
||
{
|
||
var room = await _sqlSugar.Queryable<Room>().FirstAsync(x => x.RoomNum == roomNum && x.IsDelete == false);
|
||
if (room == null)
|
||
{
|
||
throw Oops.Oh("会议号无效");
|
||
}
|
||
return room.Adapt<RoomOutputDTO>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取房间rtc token
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("tk/rtc")]
|
||
public async Task<string> GetRTCToken([FromQuery] string roomNum)
|
||
{
|
||
//var privilegeExpiredTs = _configuration["Agora:tokenExpireTimeInSecond"].ToInt32() + Utils.getTimestamp();
|
||
|
||
return new RtcTokenBuilder2().buildTokenWithUserAccount(
|
||
_configuration["Agora:appId"],
|
||
_configuration["Agora:appSecret"],
|
||
roomNum,
|
||
Account,
|
||
RtcTokenBuilder2.Role.ROLE_PUBLISHER,
|
||
_configuration["Agora:tokenExpireTimeInSecond"].ToInt32(),
|
||
_configuration["Agora:tokenExpireTimeInSecond"].ToInt32());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 邀请用户
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpPost("invite")]
|
||
public async Task InviteUser([FromQuery] string roomId, [FromBody] string[] inviteeUids)
|
||
{
|
||
var room = await _sqlSugar.Queryable<Room>().FirstAsync(x => x.Id == roomId);
|
||
|
||
var connectIds = RedisHelper.Instance.HMGet(RedisKeyConstant.SessionManage.GetOnlineUserKey(TenantId), inviteeUids);
|
||
connectIds.RemoveWhere(x => string.IsNullOrWhiteSpace(x));
|
||
|
||
await _hubContext.Clients.Clients(connectIds).Invitation(room.RoomNum, room.RoomName, UserName);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 踢出房间
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("kickout")]
|
||
public async Task KickOut([FromQuery] string roomNum, [FromQuery] string kickUid)
|
||
{
|
||
var connectId = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetOnlineUserKey(TenantId), kickUid);
|
||
if (!string.IsNullOrWhiteSpace(connectId))
|
||
{
|
||
await _hubContext.Clients.Client(connectId).ForceExitRoom(roomNum);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开闭麦
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("oper-micr")]
|
||
public async Task Mute([FromQuery] string roomNum, [FromQuery] bool enableMicr, [FromQuery] string? uid, [FromQuery] bool? isAll = false)
|
||
{
|
||
if (isAll.HasValue && isAll.Value)
|
||
{
|
||
// 全员静音
|
||
var allUsers = RedisHelper.Instance.HGetAll<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
if (!allUsers.Any())
|
||
{
|
||
return;
|
||
}
|
||
allUsers.ForEach(x =>
|
||
{
|
||
if (x.Key != uid)
|
||
{
|
||
x.Value.EnableMicr = enableMicr;
|
||
}
|
||
});
|
||
RedisHelper.Instance.HMSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), allUsers);
|
||
|
||
await _hubContext.Clients.GroupExcept(roomNum, allUsers[uid].ConnectId).OperMicr(enableMicr);
|
||
await _hubContext.Clients.Group(roomNum).RefreshUserList();
|
||
return;
|
||
}
|
||
|
||
var userInfo = RedisHelper.Instance.HGet<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), uid);
|
||
if (userInfo == null || string.IsNullOrWhiteSpace(userInfo.ConnectId))
|
||
{
|
||
_logger.LogError($"闭麦操作,用户不存在频道!rediskey:{RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum)} uid:" + uid);
|
||
return;
|
||
}
|
||
|
||
userInfo.EnableMicr = enableMicr;
|
||
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), uid, userInfo);
|
||
|
||
await _hubContext.Clients.Clients(userInfo.ConnectId).OperMicr(enableMicr);
|
||
await _hubContext.Clients.Group(roomNum).RefreshUserList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开关闭摄像头
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("oper-camera")]
|
||
public async Task CloseCamera([FromQuery] string roomNum, [FromQuery] bool enableCamera, [FromQuery] string? uid, [FromQuery] bool? isAll = false)
|
||
{
|
||
if (isAll.HasValue && isAll.Value)
|
||
{
|
||
|
||
var allUsers = RedisHelper.Instance.HGetAll<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
if (!allUsers.Any())
|
||
{
|
||
return;
|
||
}
|
||
allUsers.ForEach(x =>
|
||
{
|
||
if (x.Key != uid)
|
||
{
|
||
x.Value.EnableCamera = enableCamera;
|
||
}
|
||
});
|
||
|
||
//allUsers.ForEach(x => x.Value.EnableCamera = enableCamera);
|
||
RedisHelper.Instance.HMSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), allUsers);
|
||
|
||
// 全员开关闭摄像头
|
||
await _hubContext.Clients.GroupExcept(roomNum, allUsers[uid].ConnectId).OperCamera(enableCamera);
|
||
await _hubContext.Clients.Group(roomNum).RefreshUserList();
|
||
return;
|
||
}
|
||
|
||
var userInfo = RedisHelper.Instance.HGet<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), uid);
|
||
if (userInfo == null || string.IsNullOrWhiteSpace(userInfo.ConnectId))
|
||
{
|
||
_logger.LogError($"关闭摄像头操作,用户不存在频道!rediskey:{RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum)} uid:" + uid);
|
||
return;
|
||
}
|
||
|
||
userInfo.EnableCamera = enableCamera;
|
||
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), uid, userInfo);
|
||
|
||
await _hubContext.Clients.Clients(userInfo.ConnectId).OperCamera(enableCamera);
|
||
await _hubContext.Clients.Group(roomNum).RefreshUserList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 同步视图
|
||
/// </summary>
|
||
/// <param name="type"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("sync-view")]
|
||
public async Task ChangeView([FromQuery] string roomNum, [FromQuery] string type)
|
||
{
|
||
await _hubContext.Clients.Groups(roomNum).RefreshView(type);
|
||
}
|
||
|
||
#region 文件分享
|
||
/// <summary>
|
||
/// 分享上传文件
|
||
/// </summary>
|
||
/// <param name="inputDTO"></param>
|
||
/// <returns></returns>
|
||
[HttpPost("file")]
|
||
public async Task<bool> AddFile([FromBody] ShareFileInputDTO inputDTO)
|
||
{
|
||
var entity = inputDTO.Adapt<ShareFile>();
|
||
entity.Id = YitIdHelper.NextId().ToString();
|
||
entity.UserId = UId;
|
||
|
||
return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除文件
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpDelete("file")]
|
||
public async Task<bool> DeleteFile([FromBody] List<string> ids)
|
||
{
|
||
return await _sqlSugar.Updateable<ShareFile>()
|
||
.SetColumns(x => x.IsDelete == true)
|
||
.Where(x => ids.Contains(x.Id))
|
||
.ExecuteCommandHasChangeAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取分享文件列表
|
||
/// </summary>
|
||
/// <param name="roomId">房间Id</param>
|
||
/// <param name="pagedBaseDto"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("file")]
|
||
public async Task<PagedResult<ShareFileOutputDTO>> GetFilesList([FromQuery] string roomId, [FromQuery] string? keyword, [FromQuery] PagedBaseDto pagedBaseDto)
|
||
{
|
||
RefAsync<int> total = 0;
|
||
var list = await _sqlSugar.Queryable<ShareFile>()
|
||
.LeftJoin<User>((sf, u) => sf.UserId == u.Id)
|
||
.Where((sf, u) => sf.IsDelete == false && sf.RoomId == roomId)
|
||
.WhereIF(!string.IsNullOrWhiteSpace(keyword), (sf, u) => sf.FileName.Contains(keyword))
|
||
.Select((sf, u) => new ShareFileOutputDTO
|
||
{
|
||
Id = sf.Id,
|
||
UserId = u.Id,
|
||
UserName = u.UserName,
|
||
FileName = sf.FileName,
|
||
FileUrl = sf.FileUrl,
|
||
RoomId = sf.RoomId,
|
||
Size = sf.Size,
|
||
ModifyTime = sf.ModifyTime,
|
||
DownloadCount = sf.DownloadCount,
|
||
}).ToPageListAsync(pagedBaseDto.PageIndex, pagedBaseDto.PageSize, total);
|
||
|
||
return PagedResult<ShareFileOutputDTO>.Create(list, total.Value);
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 获取文件上传url
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("up-fileurl")]
|
||
public async Task<IActionResult> GetUploadUrl([FromQuery] string roomNum, [FromQuery] string fileSuffix)
|
||
{
|
||
return Ok(_ossHelper.GetUploadUrl($@"share_file/{TenantId}/{roomNum}", Guid.NewGuid().ToString("N") + "." + fileSuffix));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取文件下载地址
|
||
/// </summary>
|
||
/// <param name="fileUrl"></param>
|
||
/// <param name="fileId">文件Id</param>
|
||
/// <returns></returns>
|
||
[HttpGet("file-dw-url")]
|
||
public async Task<string> GetDownloadUrl([FromQuery] string fileUrl, [FromQuery] string fileId)
|
||
{
|
||
await _sqlSugar.Updateable<ShareFile>()
|
||
.SetColumns(x => x.DownloadCount == x.DownloadCount + 1)
|
||
.Where(x => x.Id == fileId).ExecuteCommandAsync();
|
||
|
||
return _ossHelper.GetAccessFileUrl(fileUrl);
|
||
}
|
||
#endregion
|
||
}
|
||
}
|