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 { /// /// 会议室接口 /// [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 _hubContext; private readonly ILogger _logger; public RoomController(ISqlSugarClient sqlSugar, IConfiguration configuration, OssHelper ossHelper, AgoraHelper agoraHelper, IHubContext hubContext, ILogger logger) { this._sqlSugar = sqlSugar; this._configuration = configuration; this._ossHelper = ossHelper; this._agoraHelper = agoraHelper; this._hubContext = hubContext; this._logger = logger; } ///// ///// 获取会议室管理员 ///// ///// //[HttpGet("manager")] //public async Task> GetRoomManager([FromQuery] string roomId) //{ // return await _sqlSugar.Queryable() // .Where(x => x.RoomId == roomId) // .Select(x => x.UserId) // .ToListAsync(); //} /// /// 设置房间管理员 /// /// [HttpPost("manager")] public async Task SetRoomManager([FromQuery] string roomId, [FromBody] List userIds) { var entities = userIds.ConvertAll(x => new RoomManager { RoomId = roomId, UserId = x }); return await _sqlSugar.Insertable(entities).ExecuteCommandAsync() > 0; } /// /// 取消房间管理员 /// /// [HttpDelete("manager")] public async Task DelRoomManager([FromQuery] string roomId, [FromBody] List userIds) { return await _sqlSugar.Deleteable() .Where(x => x.RoomId == roomId && userIds.Contains(x.UserId)) .ExecuteCommandAsync() > 0; } /// /// 查询用户信息 /// /// [HttpGet("user")] public async Task> GetUsers([FromQuery] string roomNum) { var channelUsers = RedisHelper.Instance.HVals(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum)); if (channelUsers.IsNullOrEmpty()) { return new List(); } var uids = channelUsers.Select(x => x.UID); var users = await _sqlSugar.Queryable() .Where(x => uids.Contains(x.Id)) .ToListAsync(); var managerIds = await _sqlSugar.Queryable() .InnerJoin((rm, r) => r.Id == rm.RoomId) .Where((rm, r) => r.RoomNum == roomNum) .Select((rm, r) => rm.UserId) .ToListAsync(); var result = users.Adapt>(); result.ForEach(x => { x.IsManager = 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(); //} //var accounts = data.broadcasters.ConvertAll(x => x.ToString()); //var users = await _sqlSugar.Queryable() // .Where(x => accounts.Contains(x.Account)) // .ToListAsync(); //var managerIds = await _sqlSugar.Queryable() // .InnerJoin((rm, r) => r.Id == rm.RoomId) // .Where((rm, r) => r.RoomNum == roomNum) // .Select((rm, r) => rm.UserId) // .ToListAsync(); //var result = users.Adapt>(); //result.ForEach(x => x.IsManager = managerIds.Contains(x.Id)); //return result; #endregion } /// /// 检验房间是否存在 /// /// [HttpGet("checkout"), AllowAnonymous] public async Task ExistsRoom([FromQuery] string roomNum) { return await _sqlSugar.Queryable().AnyAsync(x => x.RoomNum == roomNum && x.IsDelete == false); } /// /// 获取单个会议室信息 /// /// [HttpGet("{roomNum}")] public async Task GetRoom([FromRoute] string roomNum) { var room = await _sqlSugar.Queryable().FirstAsync(x => x.RoomNum == roomNum && x.IsDelete == false); if (room == null) { throw Oops.Oh("会议号无效"); } return room.Adapt(); } /// /// 获取房间rtc token /// /// [HttpGet("tk/rtc")] public async Task 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()); } /// /// 邀请用户 /// /// [HttpPost("invite")] public async Task InviteUser([FromQuery] string roomId, [FromBody] string[] inviteeUids) { var room = await _sqlSugar.Queryable().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); } /// /// 踢出房间 /// /// [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); } } /// /// 开闭麦 /// /// [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(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum)); if (!allUsers.Any()) { return; } allUsers.ForEach(x => x.Value.EnableMicr = enableMicr); RedisHelper.Instance.HMSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), allUsers); await _hubContext.Clients.Group(roomNum).OperMicr(enableMicr); await _hubContext.Clients.Group(roomNum).RefreshUserList(); return; } var userInfo = RedisHelper.Instance.HGet(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(); } /// /// 开关闭摄像头 /// /// [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(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum)); if (!allUsers.Any()) { return; } allUsers.ForEach(x => x.Value.EnableCamera = enableCamera); RedisHelper.Instance.HMSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), allUsers); // 全员开关闭摄像头 await _hubContext.Clients.Group(roomNum).OperCamera(enableCamera); await _hubContext.Clients.Group(roomNum).RefreshUserList(); return; } var userInfo = RedisHelper.Instance.HGet(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(); } #region 文件分享 /// /// 分享上传文件 /// /// /// [HttpPost("file")] public async Task AddFile([FromBody] ShareFileInputDTO inputDTO) { var entity = inputDTO.Adapt(); entity.Id = YitIdHelper.NextId().ToString(); entity.UserId = UId; return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0; } /// /// 删除文件 /// /// [HttpDelete("file")] public async Task DeleteFile([FromBody] List ids) { return await _sqlSugar.Updateable() .SetColumns(x => x.IsDelete == true) .Where(x => ids.Contains(x.Id)) .ExecuteCommandHasChangeAsync(); } /// /// 获取分享文件列表 /// /// 房间Id /// /// [HttpGet("file")] public async Task> GetFilesList([FromQuery] string roomId, [FromQuery] string? keyword, [FromQuery] PagedBaseDto pagedBaseDto) { RefAsync total = 0; var list = await _sqlSugar.Queryable() .LeftJoin((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.Create(list, total.Value); } /// /// 获取文件上传url /// /// [HttpGet("up-fileurl")] public async Task GetUploadUrl([FromQuery] string roomNum, [FromQuery] string fileSuffix) { return Ok(_ossHelper.GetUploadUrl($@"share_file/{TenantId}/{roomNum}", Guid.NewGuid().ToString("N") + "." + fileSuffix)); } /// /// 获取文件下载地址 /// /// /// 文件Id /// [HttpGet("file-dw-url")] public async Task GetDownloadUrl([FromQuery] string fileUrl, [FromQuery] string fileId) { await _sqlSugar.Updateable() .SetColumns(x => x.DownloadCount == x.DownloadCount + 1) .Where(x => x.Id == fileId).ExecuteCommandAsync(); return _ossHelper.GetAccessFileUrl(fileUrl); } #endregion } }