diff --git a/WGShare.API/Controllers/Frontend/RoomController.cs b/WGShare.API/Controllers/Frontend/RoomController.cs index 34cff6a..0b14d49 100644 --- a/WGShare.API/Controllers/Frontend/RoomController.cs +++ b/WGShare.API/Controllers/Frontend/RoomController.cs @@ -62,29 +62,22 @@ namespace WGShare.API.Controllers.Frontend [HttpPost("manager")] public async Task SetRoomManager([FromBody] RoomManagerInputDTO inputDTO) { - var user = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum), inputDTO.UserId); - + var users = RedisHelper.Instance.HVals(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum)); + if (users.Count(x => x.IsRoomManager || x.RoleId == ((int)RoleEnums.Admin).ToString()) >= 32) + { + throw Oops.Oh("房间已达到20个发言人限制。请移除一位或联系管理员。"); + } + var user = users.FirstOrDefault(x => x.UID == inputDTO.UserId); if (user == null) { throw Oops.Oh("用户已不在房间内!"); } - //var entities = new RoomManager - //{ - // RoomId = inputDTO.RoomId, - // UserId = inputDTO.UserId - //}; - - user.IsRoomManager = true; - //await _sqlSugar.Storageable(entities) - // .SplitInsert(x => !x.Any()) - // .ToStorage().AsInsertable.ExecuteCommandAsync(); - RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum), inputDTO.UserId, user); - await _hubContext.Clients.Group(inputDTO.RoomNum).ManagerRefresh(user); + await _hubContext.Clients.Group(inputDTO.RoomNum).ManagerRefresh(user, UId); } /// @@ -101,14 +94,25 @@ namespace WGShare.API.Controllers.Frontend throw Oops.Oh("用户已不在房间内!"); } - //await _sqlSugar.Deleteable() - // .Where(x => x.RoomId == inputDTO.RoomId && x.UserId == inputDTO.UserId) - // .ExecuteCommandAsync(); - user.IsRoomManager = false; RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum), inputDTO.UserId, user); - await _hubContext.Clients.Group(inputDTO.RoomNum).ManagerRefresh(user); + // 判断是否显示用户 + var showUserId = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), inputDTO.RoomNum); + if (showUserId == inputDTO.UserId) + { + // 取消显示用户,设置显示管理员 + var users = RedisHelper.Instance.HVals(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum)); + var showUser = users.FirstOrDefault(x => x.RoleId == ((int)RoleEnums.Admin).ToString() || x.IsRoomManager); + if (showUser != null) + { + RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), inputDTO.RoomNum, showUser.UID); + await _hubContext.Clients.Group(inputDTO.RoomNum).ShowUser(showUser.UID, showUser.UserName, string.Empty, string.Empty); + } + + } + + await _hubContext.Clients.Group(inputDTO.RoomNum).ManagerRefresh(user, UId); } /// @@ -319,17 +323,6 @@ namespace WGShare.API.Controllers.Frontend await _hubContext.Clients.Group(roomNum).OperCamera(userInfo, UId); } - ///// - ///// 同步视图 - ///// - ///// - ///// - //[HttpGet("sync-view")] - //public async Task ChangeView([FromQuery] string roomNum, [FromQuery] string type) - //{ - // await _hubContext.Clients.Groups(roomNum).RefreshView(type); - //} - /// /// 全员观看 /// @@ -403,20 +396,37 @@ namespace WGShare.API.Controllers.Frontend }; using (var pipe = RedisHelper.Instance.StartPipe()) { - //// 进房第一人,则设置全员看ta - //var script = $@"local exists = redis.call('HLEN', KEYS[1]) - // if exists == 0 then redis.call('HSET', KEYS[2], ARGV[1], ARGV[2]) end - // return exists"; - //pipe.Eval(script, [RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId)], roomNum, UId); + + if (RoleId == RoleEnums.Admin) + { + // 管理员进房,如果没有全员看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); - pipe.EndPipe(); + var results = pipe.EndPipe(); + + // 判断,如果有全员看ta,则通知 + if (RoleId == RoleEnums.Admin && !results.IsNullOrEmpty() && results[0].ObjToInt() == 1) + await _hubContext.Clients.Group(roomNum).ShowUser(UId, UserName, UId, UserName); } await _hubContext.Groups.AddToGroupAsync(ConnectionId, roomNum); await _hubContext.Clients.GroupExcept(roomNum, ConnectionId).UserJoined(userInfo); + } /// @@ -440,7 +450,17 @@ namespace WGShare.API.Controllers.Frontend pipe.HDel(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), UId); // 删除用户已参与频道 pipe.Del(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(UId)); - pipe.EndPipe(); + var result = pipe.EndPipe(); + if (!result.IsNullOrEmpty() && result[0].ObjToInt() != -1) + { + var users = RedisHelper.Instance.HVals(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum)); + var showUser = users.FirstOrDefault(x => x.RoleId == ((int)RoleEnums.Admin).ToString() || x.IsRoomManager); + 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); @@ -485,22 +505,46 @@ namespace WGShare.API.Controllers.Frontend var channelUserInfos = RedisHelper.Instance.HVals(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum)); var polledUserIds = RedisHelper.Instance.SMembers(RedisKeyConstant.Data.GetPolledUserId(TenantId, roomNum)); - // 排除已轮询的用户 - var userInfos = channelUserInfos.Where(x => !polledUserIds.Contains(x.UID) && x.RoleId != ((int)RoleEnums.Admin).ToString()).Take(count).ToList(); + // 使用 HashSet 提高查找效率 + var polledUserIdsSet = new HashSet(polledUserIds); + + // 排除管理员和发言人 + var candidates = channelUserInfos.Where(x => x.RoleId != ((int)RoleEnums.Admin).ToString() && !x.IsRoomManager); + + // 使用 HashSet 提高查找效率 + var userInfos = new List(); + var takenUids = new HashSet(); + + // 从候选者中排除上次轮询的用户,获取指定数量的用户 + 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 takeCount = count - userInfos.Count < 0 ? 0 : count - userInfos.Count; - userInfos.AddRange(channelUserInfos.Take(takeCount)); - // 删除记录,重新记录 + var remainingCandidates = candidates.Where(x => !takenUids.Contains(x.UID)); + userInfos.AddRange(remainingCandidates.Take(count - userInfos.Count)); + // 如果我们从所有用户中重新选择,清除之前的记录 RedisHelper.Instance.Del(RedisKeyConstant.Data.GetPolledUserId(TenantId, roomNum)); } - var watchUids = userInfos.Select(x => x.UID).ToArray(); - RedisHelper.Instance.SAdd(RedisKeyConstant.Data.GetPolledUserId(TenantId, roomNum), watchUids); - _hubContext.Clients.Group(roomNum).Watch(watchUids); + 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; + return userInfos; } /// diff --git a/WGShare.API/Hubs/IMessageClient.cs b/WGShare.API/Hubs/IMessageClient.cs index 8801d2a..ab64a12 100644 --- a/WGShare.API/Hubs/IMessageClient.cs +++ b/WGShare.API/Hubs/IMessageClient.cs @@ -14,7 +14,7 @@ namespace WGShare.API.Hubs /// /// /// - Task ReceiveMessage(string uid, string userName, string message,long timestamp); + Task ReceiveMessage(string uid, string userName, string message, long timestamp); /// @@ -56,7 +56,7 @@ namespace WGShare.API.Hubs /// 全员观看 /// /// - Task ShowUser(string uid, string uname,string operUid, string operUserName); + Task ShowUser(string uid, string uname, string operUid, string operUserName); /// /// 用户加入频道回调 @@ -96,14 +96,15 @@ namespace WGShare.API.Hubs /// /// /// - Task OperCamera(ChannelUserInfo user,string operUid); + Task OperCamera(ChannelUserInfo user, string operUid); /// /// 管理员用户信息刷新 /// /// + /// /// - Task ManagerRefresh(ChannelUserInfo user); + Task ManagerRefresh(ChannelUserInfo user, string operUid); /// /// 强制登出 @@ -123,6 +124,6 @@ namespace WGShare.API.Hubs /// 接受监控用户 /// /// - void Watch(string[] watchUids); + Task Watch(string[] watchUids); } } diff --git a/WGShare.API/WGShare.API.xml b/WGShare.API/WGShare.API.xml index 11aec50..aa8d386 100644 --- a/WGShare.API/WGShare.API.xml +++ b/WGShare.API/WGShare.API.xml @@ -457,11 +457,12 @@ - + 管理员用户信息刷新 + @@ -478,6 +479,12 @@ + + + 接受监控用户 + + + 加入频道