691 lines
28 KiB
C#
691 lines
28 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 System.Security.Principal;
|
||
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.Tenant;
|
||
using WGShare.Domain.DTOs.User;
|
||
using WGShare.Domain.Entities;
|
||
using WGShare.Domain.Enums;
|
||
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>
|
||
[HttpPost("manager")]
|
||
public async Task SetRoomManager([FromBody] RoomManagerInputDTO inputDTO)
|
||
{
|
||
var users = RedisHelper.Instance.HVals<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum));
|
||
if (users.Count(x => x.IsRoomManager || x.RoleId == ((int)RoleEnums.Admin).ToString() || x.RoleId == ((int)RoleEnums.RoomManager).ToString()) >= 12)
|
||
{
|
||
throw Oops.Oh("房间已达到12个发言人限制。请移除一位发言人");
|
||
}
|
||
var user = users.FirstOrDefault(x => x.UID == inputDTO.UserId);
|
||
if (user == null)
|
||
{
|
||
throw Oops.Oh("用户已不在房间内!");
|
||
}
|
||
|
||
user.IsRoomManager = true;
|
||
|
||
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum), inputDTO.UserId, user);
|
||
|
||
await _hubContext.Clients.Group(inputDTO.RoomNum).ManagerRefresh(user, UId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取消房间管理员
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpDelete("manager")]
|
||
public async Task DelRoomManager([FromBody] RoomManagerInputDTO inputDTO)
|
||
{
|
||
|
||
var user = RedisHelper.Instance.HGet<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum), inputDTO.UserId);
|
||
if (user == null)
|
||
{
|
||
throw Oops.Oh("用户已不在房间内!");
|
||
}
|
||
|
||
user.IsRoomManager = false;
|
||
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum), inputDTO.UserId, user);
|
||
|
||
// 判断是否显示用户
|
||
var showUserId = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), inputDTO.RoomNum);
|
||
if (showUserId == inputDTO.UserId || showUserId == user.ScreenShareId)
|
||
{
|
||
|
||
//var users = RedisHelper.Instance.HVals<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum));
|
||
//var showUser = users.FirstOrDefault(x => x.RoleId == ((int)RoleEnums.Admin).ToString() || x.IsRoomManager || x.RoleId == ((int)RoleEnums.RoomManager).ToString());
|
||
//if (showUser != null)
|
||
//{
|
||
|
||
// 取消显示用户,设置显示当前操作的管理员
|
||
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), inputDTO.RoomNum, UId);
|
||
await _hubContext.Clients.Group(inputDTO.RoomNum).ShowUser(UId, UserName, string.Empty, string.Empty);
|
||
//}
|
||
|
||
}
|
||
|
||
await _hubContext.Clients.Group(inputDTO.RoomNum).ManagerRefresh(user, UId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询房间中所有用户信息
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("user")]
|
||
public async Task<IEnumerable<ChannelUserInfo>> GetUsers([FromQuery] string roomNum)
|
||
{
|
||
var channelUsers = RedisHelper.Instance.HVals<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
if (channelUsers.IsNullOrEmpty())
|
||
{
|
||
return new List<ChannelUserInfo>();
|
||
}
|
||
|
||
return channelUsers;
|
||
#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("user/{uid}")]
|
||
public async Task<ChannelUserInfo> GetUser([FromQuery] string roomNum, [FromRoute] string uid)
|
||
{
|
||
var channelUser = RedisHelper.Instance.HGet<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), uid);
|
||
if (channelUser == null)
|
||
{
|
||
throw Oops.Oh("用户不在房间内!");
|
||
}
|
||
|
||
return channelUser;
|
||
}
|
||
|
||
/// <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,
|
||
"*",
|
||
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);
|
||
|
||
|
||
await _hubContext.Clients.Users(inviteeUids).Invitation(room.RoomNum, room.RoomName, UserName);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 踢出房间
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("kickout")]
|
||
public async Task KickOut([FromQuery] string roomNum, [FromQuery] string kickUid)
|
||
{
|
||
await _hubContext.Clients.User(kickUid).ForceExitRoom(roomNum);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 全部人开闭麦
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("mute-all")]
|
||
public async Task MuteAll([FromQuery] string roomNum, [FromQuery] bool enableMicr)
|
||
{
|
||
// 全员静音
|
||
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.Group(roomNum).OperAllMicr(enableMicr, UId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 单用户开闭麦
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("oper-micr")]
|
||
public async Task Mute([FromQuery] string roomNum, [FromQuery] bool enableMicr, [FromQuery] string uid)
|
||
{
|
||
|
||
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);
|
||
|
||
_logger.LogInformation($@"开闭麦克分,推送一次,roomNum:{roomNum},enableMicr:{enableMicr},uid:{uid}");
|
||
// 通知所有人该用户麦克风状态
|
||
await _hubContext.Clients.Group(roomNum).OperMicr(userInfo, UId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开关闭摄像头
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("oper-camera")]
|
||
public async Task CloseCamera([FromQuery] string roomNum, [FromQuery] bool enableCamera, [FromQuery] string uid)
|
||
{
|
||
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.Group(roomNum).OperCamera(userInfo, UId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 全员观看
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("show-user")]
|
||
public async Task<string> GetShowUser([FromQuery] string roomNum)
|
||
{
|
||
// 获取全员观看用户
|
||
var showUserId = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), roomNum);
|
||
if (!string.IsNullOrWhiteSpace(showUserId))
|
||
{
|
||
return showUserId;
|
||
}
|
||
|
||
// 获取全部用户
|
||
var uids = RedisHelper.Instance.HKeys(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
if (uids.IsNullOrEmpty())
|
||
{
|
||
throw Oops.Oh("无效会议号!");
|
||
}
|
||
|
||
return uids.FirstOrDefault();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置全员观看
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpPost("show-user")]
|
||
public async Task SetShowUser([FromQuery] string roomNum, [FromQuery] string uid, [FromQuery] string uname)
|
||
{
|
||
// 设置房间全员观看用户
|
||
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), roomNum, uid);
|
||
|
||
//var connectId = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetOnlineUserKey(TenantId), UId);
|
||
//if (!string.IsNullOrWhiteSpace(connectId))
|
||
//{
|
||
// await _hubContext.Clients.GroupExcept(roomNum, connectId).ShowUser();
|
||
//}
|
||
|
||
await _hubContext.Clients.Group(roomNum).ShowUser(uid, uname, UId, UserName);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加入频道
|
||
/// </summary>
|
||
/// <param name="roomNum"></param>
|
||
/// <param name="enableMicr"></param>
|
||
/// <param name="enableCamera"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("join"), Obsolete("废弃,请使用Socker接口 JoinChannel")]
|
||
public async Task JoinChannel([FromQuery] string roomNum, [FromQuery] bool enableMicr = false, [FromQuery] bool enableCamera = false)
|
||
{
|
||
//throw Oops.("接口已废弃");
|
||
//var isRoomManager = await _sqlSugar.Queryable<RoomManager>()
|
||
// .InnerJoin<Room>((rm, r) => r.Id == rm.RoomId)
|
||
// .Where((rm, r) => r.RoomNum == roomNum && rm.UserId == UId)
|
||
// .AnyAsync();
|
||
|
||
var userInfo = new ChannelUserInfo
|
||
{
|
||
UID = UId,
|
||
UserName = UserName,
|
||
EnableCamera = enableCamera,
|
||
EnableMicr = enableMicr,
|
||
ConnectId = ConnectionId,
|
||
Account = Account,
|
||
ScreenShareId = ScreenShareId,
|
||
RoleId = ((int)RoleId).ToString(),
|
||
RoleName = RoleId.GetDescription(),
|
||
IsRoomManager = false
|
||
};
|
||
using (var pipe = RedisHelper.Instance.StartPipe())
|
||
{
|
||
|
||
if (RoleId == RoleEnums.Admin || RoleId == RoleEnums.RoomManager)
|
||
{
|
||
// 管理员进房,如果没有全员看ta,则设置
|
||
var script = @"local hashKey = KEYS[1]
|
||
local field = ARGV[1]
|
||
local value = ARGV[2]
|
||
|
||
if redis.call('HEXISTS', hashKey, field) == 0 then
|
||
redis.call('HSET', hashKey, field, value)
|
||
return 1
|
||
else
|
||
return 0
|
||
end";
|
||
pipe.Eval(script, [RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId)], roomNum, UId);
|
||
|
||
}
|
||
|
||
// 记录频道得用户信息
|
||
pipe.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), UId, userInfo);
|
||
// 记录用户已参与频道
|
||
pipe.Set(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(UId), roomNum);
|
||
var results = pipe.EndPipe();
|
||
|
||
// 判断,如果有全员看ta,则通知
|
||
if ((RoleId == RoleEnums.Admin || RoleId == RoleEnums.RoomManager) && !results.IsNullOrEmpty() && results[0].ObjToInt() == 1)
|
||
await _hubContext.Clients.Group(roomNum).ShowUser(UId, UserName, string.Empty, string.Empty);
|
||
}
|
||
await _hubContext.Groups.AddToGroupAsync(ConnectionId, roomNum);
|
||
await _hubContext.Clients.GroupExcept(roomNum, ConnectionId).UserJoined(userInfo);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 单用户离开频道
|
||
/// </summary>
|
||
/// <param name="roomNum"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("leave"), Obsolete("废弃,请使用Socker接口 leavelChannel")]
|
||
public async Task LevelChannel([FromQuery] string roomNum)
|
||
{
|
||
|
||
using (var pipe = RedisHelper.Instance.StartPipe())
|
||
{
|
||
// 判断,如果有全员看ta,则删除
|
||
var script = $@"local value = redis.call('HGET', KEYS[1], ARGV[1])
|
||
if value == ARGV[2] or value == ARGV[3] then
|
||
return redis.call('HDEL', KEYS[1], ARGV[1])
|
||
else return -1 end";
|
||
// 执行 eval 命令
|
||
pipe.Eval(script, [RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId)], roomNum, UId, ScreenShareId);
|
||
// 删除频道中得该用户
|
||
pipe.HDel(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), UId);
|
||
// 删除用户已参与频道
|
||
pipe.Del(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(UId));
|
||
var result = pipe.EndPipe();
|
||
if (!result.IsNullOrEmpty() && result[0].ObjToInt() != -1)
|
||
{
|
||
var users = RedisHelper.Instance.HVals<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
var showUser = users.FirstOrDefault(x => x.RoleId == ((int)RoleEnums.Admin).ToString() || x.IsRoomManager || x.RoleId == ((int)RoleEnums.RoomManager).ToString());
|
||
if (showUser != null)
|
||
{
|
||
// 通知全员看ta
|
||
await _hubContext.Clients.Group(roomNum).ShowUser(showUser.UID, showUser.UserName, string.Empty, string.Empty);
|
||
}
|
||
}
|
||
}
|
||
|
||
await _hubContext.Clients.GroupExcept(roomNum, ConnectionId).UserLeave(UId);
|
||
await _hubContext.Groups.RemoveFromGroupAsync(ConnectionId, roomNum);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 全部离开频道
|
||
/// </summary>
|
||
/// <param name="roomNum"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("leave-all")]
|
||
public async Task AllLevelChannel([FromQuery] string roomNum)
|
||
{
|
||
var uids = RedisHelper.Instance.HKeys(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum)).ToList();
|
||
using (var pipe = RedisHelper.Instance.StartPipe())
|
||
{
|
||
// 删除大家都看ta
|
||
pipe.HDel(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), roomNum);
|
||
// 删除频道里得用户
|
||
pipe.Del(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
if (!uids.IsNullOrEmpty())
|
||
{
|
||
var keys = uids.ConvertAll(uid => RedisKeyConstant.SessionManage.GetUserJoinChannelKey(uid));
|
||
pipe.Del(keys.ToArray());
|
||
}
|
||
|
||
pipe.EndPipe();
|
||
}
|
||
|
||
await _hubContext.Clients.Group(roomNum).AllLeave();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取监控的轮询用户
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("polling")]
|
||
public async Task<IEnumerable<ChannelUserInfo>> GetPollingUser([FromQuery] string roomNum, [FromQuery] int count)
|
||
{
|
||
// 获取当前房间所有人id
|
||
var channelUserInfos = RedisHelper.Instance.HVals<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
var polledUserIds = RedisHelper.Instance.SMembers(RedisKeyConstant.Data.GetPolledUserId(TenantId, roomNum));
|
||
|
||
// 使用 HashSet 提高查找效率
|
||
var polledUserIdsSet = new HashSet<string>(polledUserIds);
|
||
|
||
// 排除管理员和发言人
|
||
var candidates = channelUserInfos.Where(x => x.RoleId != ((int)RoleEnums.Admin).ToString() && !x.IsRoomManager && x.RoleId != ((int)RoleEnums.RoomManager).ToString());
|
||
|
||
// 使用 HashSet 提高查找效率
|
||
var userInfos = new List<ChannelUserInfo>();
|
||
var takenUids = new HashSet<string>();
|
||
|
||
// 从候选者中排除上次轮询的用户,获取指定数量的用户
|
||
foreach (var candidate in candidates)
|
||
{
|
||
if (userInfos.Count >= count)
|
||
break;
|
||
|
||
if (!polledUserIdsSet.Contains(candidate.UID))
|
||
{
|
||
userInfos.Add(candidate);
|
||
takenUids.Add(candidate.UID);
|
||
}
|
||
}
|
||
|
||
// 如果数量不足,则从未选择的候选者中取足
|
||
if (userInfos.Count < count)
|
||
{
|
||
var remainingCandidates = candidates.Where(x => !takenUids.Contains(x.UID));
|
||
userInfos.AddRange(remainingCandidates.Take(count - userInfos.Count));
|
||
// 如果我们从所有用户中重新选择,清除之前的记录
|
||
RedisHelper.Instance.Del(RedisKeyConstant.Data.GetPolledUserId(TenantId, roomNum));
|
||
}
|
||
|
||
if (!userInfos.IsNullOrEmpty())
|
||
{
|
||
var watchUids = userInfos.Select(x => x.UID).ToArray();
|
||
RedisHelper.Instance.SAdd(RedisKeyConstant.Data.GetPolledUserId(TenantId, roomNum), watchUids);
|
||
await _hubContext.Clients.Group(roomNum).Watch(watchUids);
|
||
}
|
||
|
||
return userInfos;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 申请发言
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("apply-speak")]
|
||
public async Task ApplySpeak([FromQuery] string roomNum)
|
||
{
|
||
var channelUsers = RedisHelper.Instance.HVals<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum));
|
||
if (channelUsers.IsNullOrEmpty())
|
||
{
|
||
return;
|
||
}
|
||
var connectionIds = channelUsers.Where(x => x.RoleId == ((int)RoleEnums.Admin).ToString() || x.RoleId == ((int)RoleEnums.RoomManager).ToString()).Select(x => x.ConnectId);
|
||
|
||
if (connectionIds.Any())
|
||
{
|
||
await _hubContext.Clients.Clients(connectionIds).ApplyToSpeak(UId, UserName);
|
||
}
|
||
}
|
||
|
||
|
||
#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
|
||
|
||
/// <summary>
|
||
/// 获取签到列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("sign-in")]
|
||
public async Task<List<UserSignInListDto>> GetSignInList()
|
||
{
|
||
var list = await _sqlSugar.Queryable<UserSignInList>()
|
||
.Where(x => x.UId == UId)
|
||
.ToListAsync();
|
||
|
||
return list.Adapt<List<UserSignInListDto>>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提交签到
|
||
/// </summary>
|
||
/// <param name="list"></param>
|
||
/// <returns></returns>
|
||
[HttpPost("sign-in")]
|
||
public async Task SignIn([FromBody] List<UserSignInRecordDto> list)
|
||
{
|
||
var entitys = list.Adapt<List<UserSignInRecord>>();
|
||
entitys.ForEach(x => x.UId = UId);
|
||
|
||
await _sqlSugar.Insertable(entitys).ExecuteCommandAsync();
|
||
}
|
||
}
|
||
}
|