1优化重启删除redis问题

This commit is contained in:
youngq 2024-08-09 16:24:26 +08:00
parent 765d241d5b
commit d3aff3ae77
19 changed files with 561 additions and 250 deletions

View File

@ -7,6 +7,7 @@ using System.Configuration;
using System.Security.Claims;
using WGShare.API.Controllers.Basic;
using WGShare.API.Helpers;
using WGShare.Domain.Constant;
using WGShare.Domain.DTOs.Login;
using WGShare.Domain.Entities;
using WGShare.Domain.FriendlyException;
@ -84,7 +85,7 @@ namespace WGShare.API.Controllers
btnAutn.Add(new Claim("ssid", user.ScreenShareId));
var refreshToken = Guid.NewGuid().ToString();
RedisHelper.Instance.Set($@"refresh:{refreshToken}", user, TimeSpan.FromDays(30).TotalSeconds.ToInt32());
RedisHelper.Instance.Set(RedisKeyConstant.Data.GetRefreshTokenKey(refreshToken), user, TimeSpan.FromDays(30).TotalSeconds.ToInt32());
return Ok(new
{
@ -109,7 +110,7 @@ namespace WGShare.API.Controllers
[HttpPost("refresh"), AllowAnonymous]
public async Task<IActionResult> Refresh([FromQuery] string refreshToken)
{
var user = RedisHelper.Instance.Get<User>($@"refresh:{refreshToken}");
var user = RedisHelper.Instance.Get<User>(RedisKeyConstant.Data.GetRefreshTokenKey(refreshToken));
if (user == null || string.IsNullOrWhiteSpace(user.Id))
{
throw new FriendlyInternalException("登录已失效,请重新登录", null, 1403);
@ -125,8 +126,8 @@ namespace WGShare.API.Controllers
var refreshTokenNew = Guid.NewGuid().ToString();
RedisHelper.Instance.Del($@"refresh:{refreshToken}");
RedisHelper.Instance.Set($@"refresh:{refreshTokenNew}", user, TimeSpan.FromDays(30).TotalSeconds.ToInt32());
RedisHelper.Instance.Del(RedisKeyConstant.Data.GetRefreshTokenKey(refreshToken));
RedisHelper.Instance.Set(RedisKeyConstant.Data.GetRefreshTokenKey(refreshTokenNew), user, TimeSpan.FromDays(30).TotalSeconds.ToInt32());
return Ok(new
{
@ -147,7 +148,7 @@ namespace WGShare.API.Controllers
/// 匿名登录,直接进入会议室
/// </summary>
/// <returns></returns>
[HttpPost("anon-login"),Obsolete]
[HttpPost("anon-login"), Obsolete]
public async Task<IActionResult> Login([FromBody] AnonymousLoginDTO loginDTO)
{

View File

@ -1,8 +1,14 @@
using Mapster;
using Masuit.Tools;
using Masuit.Tools.Security;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileSystemGlobbing.Internal;
using MiniExcelLibs;
using Newtonsoft.Json.Linq;
using SqlSugar;
using System;
using System.Text.RegularExpressions;
using WGShare.API.Controllers.Basic;
using WGShare.API.Helpers;
using WGShare.Domain.DTOs.User;
@ -18,10 +24,13 @@ namespace WGShare.API.Controllers.Backend
public class UserController : BasicController
{
private readonly ISqlSugarClient _sqlSugar;
private readonly OssHelper _ossHelper;
public UserController(ISqlSugarClient sqlSugar)
public UserController(ISqlSugarClient sqlSugar,
OssHelper ossHelper)
{
_sqlSugar = sqlSugar;
this._ossHelper = ossHelper;
}
@ -119,16 +128,76 @@ namespace WGShare.API.Controllers.Backend
await _sqlSugar.Insertable(entity).ExecuteCommandAsync();
}
///// <summary>
///// Excel 导入用户
///// </summary>
///// <param name="file"></param>
///// <returns></returns>
//[HttpPost("import")]
//public async Task<bool> Import([FromForm] IFormFile file)
//{
// using var stream = file.OpenReadStream();
// MiniExcel.Query<ChannelUserInfo>(stream);
//}
/// <summary>
/// Excel 导入用户
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("import")]
public async Task<IActionResult> Import([FromForm] IFormFile file, [FromForm] string tenantId)
{
using var stream = file.OpenReadStream();
var rows = stream.Query<UserExcelInputDto>().ToList();
if (rows.IsNullOrEmpty())
{
throw Oops.Oh("无有效数据,请检查文件数据!");
}
var accounts = rows.Select(x => x.Account.Trim());
var repeatAccount = accounts.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => x.Key).ToHashSet();
// 去除重复账号
var distinctAccount = accounts.Except(repeatAccount);
// 数据库重复账号检查
var existsAccount = await _sqlSugar.Queryable<User>()
.Where(x => distinctAccount.Contains(x.Account))
.Select(x => x.Account)
.ToListAsync();
if (!existsAccount.IsNullOrEmpty())
{
repeatAccount.UnionWith(existsAccount);
}
if (!repeatAccount.IsNullOrEmpty())
{
// 重复账号返回结果Excel
foreach (var row in rows)
{
if (repeatAccount.Contains(row.Account))
{
row.ImportResult = "账号重复";
}
else
{
row.ImportResult = "可导入";
}
}
//FileStreamResult fileStream = null;
using var memoryStream = new MemoryStream();
memoryStream.SaveAs(rows);
memoryStream.Seek(0, SeekOrigin.Begin);
var fileName = $@"excel/{Regex.Replace(file.FileName, @"\.(xlsx|xls)$", "", RegexOptions.IgnoreCase)}_验证不通过_{DateTime.UtcNow.Ticks}.xlsx";
_ossHelper.UploadWithExpireTime(fileName, memoryStream, 1);
var fileUrl = _ossHelper.GetAccessFileUrl(fileName, 1);
return Ok((isSuccess: false, url: fileUrl));
}
var users = rows.Adapt<List<User>>();
users.ForEach(x =>
{
x.Pwd = x.Pwd.MDString();
x.ScreenShareId = UserShareIdHelper.GenerateUnique8DigitNumber();
x.TenantId = tenantId;
x.RoleId = x.RoleId == "管理员" ? "1" : "2";
});
await _sqlSugar.Insertable(users).ExecuteCommandAsync();
return Ok((isSuccess: true, url: "导入成功"));
}
}
}

View File

@ -1,6 +1,8 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar.Extensions;
using WGShare.API.Helpers;
using WGShare.Domain.Constant;
using WGShare.Domain.FriendlyException;
namespace WGShare.API.Controllers.Basic
@ -74,5 +76,33 @@ namespace WGShare.API.Controllers.Basic
return tenant;
}
}
public string ScreenShareId
{
get
{
var ssId = HttpContext.User.Claims.FirstOrDefault(x => x.Type == "ssid").Value;
if (string.IsNullOrWhiteSpace(ssId))
{
throw Oops.Oh("用户信息有误,请重新登录");
}
return ssId;
}
}
public string ConnectionId
{
get
{
var connectid = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetOnlineUserKey(TenantId), UId);
if (string.IsNullOrWhiteSpace(connectid))
{
throw Oops.Oh("用户信息有误,请重新登录");
}
return connectid;
}
}
}
}

View File

@ -15,8 +15,10 @@ 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;
@ -52,33 +54,27 @@ namespace WGShare.API.Controllers.Frontend
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)
public async Task SetRoomManager([FromQuery] string roomId, [FromQuery] string roomNum, [FromBody] string userId)
{
var entities = userIds.ConvertAll(x => new RoomManager
var entities = new RoomManager
{
RoomId = roomId,
UserId = x
});
UserId = userId
};
return await _sqlSugar.Insertable(entities).ExecuteCommandAsync() > 0;
var user = RedisHelper.Instance.HGet<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), userId);
user.IsRoomManager = true;
await _sqlSugar.Insertable(entities).ExecuteCommandAsync();
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), userId, user);
await _hubContext.Clients.Group(roomNum).ManagerRefresh(user);
}
/// <summary>
@ -86,54 +82,33 @@ namespace WGShare.API.Controllers.Frontend
/// </summary>
/// <returns></returns>
[HttpDelete("manager")]
public async Task<bool> DelRoomManager([FromQuery] string roomId, [FromBody] List<string> userIds)
public async Task DelRoomManager([FromQuery] string roomId, [FromQuery] string roomNum, [FromBody] string userId)
{
return await _sqlSugar.Deleteable<RoomManager>()
.Where(x => x.RoomId == roomId && userIds.Contains(x.UserId))
.ExecuteCommandAsync() > 0;
await _sqlSugar.Deleteable<RoomManager>()
.Where(x => x.RoomId == roomId && x.UserId == userId)
.ExecuteCommandAsync();
var user = RedisHelper.Instance.HGet<ChannelUserInfo>(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), userId);
user.IsRoomManager = false;
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), userId, user);
await _hubContext.Clients.Group(roomNum).ManagerRefresh(user);
}
/// <summary>
/// 查询用户信息
/// 查询房间中所有用户信息
/// </summary>
/// <returns></returns>
[HttpGet("user")]
public async Task<List<UserOutputDTO>> GetUsers([FromQuery] string roomNum)
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<UserOutputDTO>();
return new List<ChannelUserInfo>();
}
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;
return channelUsers;
#region
//var data = await _agoraHelper.GetChannelUserList(roomNum);
@ -244,33 +219,39 @@ namespace WGShare.API.Controllers.Frontend
}
/// <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.GroupExcept(roomNum, allUsers[UId].ConnectId).OperAllMicr(enableMicr);
}
/// <summary>
/// 单用户开闭麦
/// </summary>
/// <returns></returns>
[HttpGet("oper-micr")]
public async Task Mute([FromQuery] string roomNum, [FromQuery] bool enableMicr, [FromQuery] string? uid, [FromQuery] bool? isAll = false)
public async Task Mute([FromQuery] string roomNum, [FromQuery] bool enableMicr, [FromQuery] string uid)
{
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))
@ -282,8 +263,8 @@ namespace WGShare.API.Controllers.Frontend
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();
// 通知所有人该用户麦克风状态
await _hubContext.Clients.Group(roomNum).OperMicr(userInfo);
}
/// <summary>
@ -291,33 +272,8 @@ namespace WGShare.API.Controllers.Frontend
/// </summary>
/// <returns></returns>
[HttpGet("oper-camera")]
public async Task CloseCamera([FromQuery] string roomNum, [FromQuery] bool enableCamera, [FromQuery] string? uid, [FromQuery] bool? isAll = false)
public async Task CloseCamera([FromQuery] string roomNum, [FromQuery] bool enableCamera, [FromQuery] string uid)
{
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))
{
@ -328,8 +284,8 @@ namespace WGShare.API.Controllers.Frontend
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();
// 通知所有人该用户麦克风状态
await _hubContext.Clients.Group(roomNum).OperCamera(userInfo);
}
/// <summary>
@ -358,7 +314,7 @@ namespace WGShare.API.Controllers.Frontend
}
// 获取全员观看用户
var showUserId = RedisHelper.Instance.HGet(RedisKeyConstant.RoomManager.GetChannelShowUserKey(TenantId), roomNum);
var showUserId = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), roomNum);
if (!string.IsNullOrWhiteSpace(showUserId))
{
return showUserId;
@ -372,10 +328,10 @@ namespace WGShare.API.Controllers.Frontend
/// </summary>
/// <returns></returns>
[HttpPost("show-user")]
public async Task SetShowUser([FromQuery] string roomNum, [FromQuery] string uid)
public async Task SetShowUser([FromQuery] string roomNum, [FromQuery] string? uid)
{
// 设置房间全员观看用户
RedisHelper.Instance.HSet(RedisKeyConstant.RoomManager.GetChannelShowUserKey(TenantId), roomNum, uid);
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId), roomNum, uid);
var connectId = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetOnlineUserKey(TenantId), UId);
if (!string.IsNullOrWhiteSpace(connectId))
@ -384,6 +340,69 @@ namespace WGShare.API.Controllers.Frontend
}
}
/// <summary>
/// 加入频道
/// </summary>
/// <param name="roomNum"></param>
/// <param name="enableMicr"></param>
/// <param name="enableCamera"></param>
/// <returns></returns>
[HttpGet("join")]
public async Task JoinChannel([FromQuery] string roomNum, [FromQuery] bool enableMicr = false, [FromQuery] bool enableCamera = false)
{
var isManager = 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 = RoleId,
RoleName = ((RoleEnums)RoleId.ToInt32()).GetDescription(),
IsRoomManager = isManager
};
using (var pipe = RedisHelper.Instance.StartPipe())
{
pipe.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), UId, userInfo.ToJsonString());
pipe.HSet(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(UId), roomNum, 1);
pipe.EndPipe();
}
await _hubContext.Groups.AddToGroupAsync(ConnectionId, roomNum);
await _hubContext.Clients.GroupExcept(roomNum, ConnectionId).UserJoined(userInfo);
}
/// <summary>
/// 离开频道
/// </summary>
/// <param name="roomNum"></param>
/// <returns></returns>
[HttpGet("leave")]
public async Task LevelChannel([FromQuery] string roomNum)
{
using (var pipe = RedisHelper.Instance.StartPipe())
{
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.HDel(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(UId), roomNum);
pipe.EndPipe();
}
await _hubContext.Clients.GroupExcept(roomNum, ConnectionId).UserLeave(UId);
await _hubContext.Groups.RemoveFromGroupAsync(ConnectionId, roomNum);
}
#region
/// <summary>
/// 分享上传文件

View File

@ -1,12 +1,15 @@
using Masuit.Tools;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using SqlSugar;
using System.Configuration;
using System.Security.Claims;
using System.Text.RegularExpressions;
using WGShare.API.Controllers.Basic;
using WGShare.API.Helpers;
using WGShare.Domain.DTOs.Login;
using WGShare.Domain.DTOs.User;
using WGShare.Domain.Entities;
using WGShare.Domain.FriendlyException;

View File

@ -0,0 +1,14 @@
using System.ComponentModel;
namespace WGShare.API.Helpers
{
public static class EnumExtensions
{
public static string GetDescription(this Enum val)
{
var field = val.GetType().GetField(val.ToString());
var customAttribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute));
return customAttribute == null ? val.ToString() : ((DescriptionAttribute)customAttribute).Description;
}
}
}

View File

@ -69,16 +69,16 @@ namespace WGShare.API.Helpers
};
}
public string GetAccessFileUrl(string path)
public string GetAccessFileUrl(string path, int expireInMinutes = 1)
{
if (string.IsNullOrWhiteSpace(path) )
if (string.IsNullOrWhiteSpace(path))
{
throw Oops.Oh("路径不能为空!");
}
var urlRequest = new GeneratePresignedUriRequest(_bucketName, path)
{
Expiration = DateTimeOffset.Now.AddMinutes(1).LocalDateTime
Expiration = DateTimeOffset.Now.AddMinutes(expireInMinutes).LocalDateTime
};
return _ossClient.GeneratePresignedUri(urlRequest).ToString();
@ -95,5 +95,24 @@ namespace WGShare.API.Helpers
return result.HttpStatusCode == System.Net.HttpStatusCode.OK;
}
/// <summary>
/// 流上传文件
/// </summary>
/// <param name="objectName"></param>
/// <param name="stream"></param>
public void UploadWithExpireTime(string objectName, MemoryStream stream, int expireTimeInMinutes)
{
if (expireTimeInMinutes <= 0)
{
throw Oops.Oh("过期时间不能小于0");
}
_ossClient.PutObject(_bucketName, objectName, stream, new ObjectMetadata
{
ExpirationTime = DateTimeOffset.Now.AddMinutes(expireTimeInMinutes).DateTime,
});
}
}
}

View File

@ -1,4 +1,6 @@
namespace WGShare.API.Helpers
using WGShare.Domain.Constant;
namespace WGShare.API.Helpers
{
public class UserShareIdHelper
{
@ -16,10 +18,10 @@
{
long ticks = DateTime.UtcNow.Ticks;
var randomPart = random.Next(1000, 10000).ToString(); // 随机生成4位数字
uniqueNumber = randomPart + (ticks % 10000).ToString("D4"); // 拼接成8位数字
} while (RedisHelper.Instance.SIsMember("screen_share_id", uniqueNumber));
uniqueNumber = randomPart + (ticks % 10000).ToString("D5"); // 拼接成8位数字
} while (RedisHelper.Instance.SIsMember(RedisKeyConstant.Data.GetScreenShareIdKey, uniqueNumber));
RedisHelper.Instance.SAdd("screen_share_id", uniqueNumber);
RedisHelper.Instance.SAdd(RedisKeyConstant.Data.GetScreenShareIdKey, uniqueNumber);
return uniqueNumber;
}
}

View File

@ -1,4 +1,7 @@
namespace WGShare.API.Hubs
using WGShare.Domain.DTOs.User;
using WGShare.Domain.Entities;
namespace WGShare.API.Hubs
{
/// <summary>
/// 客户端消息
@ -30,20 +33,6 @@
/// <returns></returns>
Task ForceExitRoom(string roomNum);
/// <summary>
/// 用户开闭麦
/// </summary>
/// <param name="enableMicr"></param>
/// <returns></returns>
Task OperMicr(bool enableMicr);
/// <summary>
/// 用户开启关闭摄像头
/// </summary>
/// <param name="enableCamera"></param>
/// <returns></returns>
Task OperCamera(bool enableCamera);
/// <summary>
/// 刷新用户列表
/// </summary>
@ -68,5 +57,45 @@
/// </summary>
/// <returns></returns>
Task ShowUser();
/// <summary>
/// 用户加入频道回调
/// </summary>
/// <returns></returns>
Task UserJoined(ChannelUserInfo user);
/// <summary>
/// 用户退出频道回调
/// </summary>
/// <returns></returns>
Task UserLeave(string uid);
/// <summary>
/// 所有用户开闭麦
/// </summary>
/// <param name="enableMicr"></param>
/// <returns></returns>
Task OperAllMicr(bool enableMicr);
/// <summary>
/// 用户关闭开启麦克风
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task OperMicr(ChannelUserInfo user);
/// <summary>
/// 用户开启关闭摄像头
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task OperCamera(ChannelUserInfo user);
/// <summary>
/// 管理员用户信息刷新
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task ManagerRefresh(ChannelUserInfo user);
}
}

View File

@ -7,6 +7,7 @@ using System.Text;
using WGShare.API.Helpers;
using WGShare.Domain.Constant;
using WGShare.Domain.Entities;
using WGShare.Domain.Enums;
namespace WGShare.API.Hubs
{
@ -79,7 +80,7 @@ namespace WGShare.API.Hubs
return redis.call('HDEL', KEYS[1], ARGV[1])
else return -1 end";
// 执行 eval 命令
pipe.Eval(script, [RedisKeyConstant.RoomManager.GetChannelShowUserKey(tenant)], roomNum, uid, ssid);
pipe.Eval(script, [RedisKeyConstant.SessionManage.GetChannelShowUserKey(tenant)], roomNum, uid, ssid);
});
}
@ -101,62 +102,79 @@ namespace WGShare.API.Hubs
/// <param name="roomNum"></param>
/// <param name="enableMicr">是否关闭麦克风,默认是</param>
/// <param name="enableCamera">是否关闭摄像头,默认是</param>
[HubMethodName("joinChannel")]
[HubMethodName("joinChannel"), Obsolete("废弃请使用Api接口 JoinChannel")]
public async Task JoinChannel(string roomNum, bool enableMicr = true, bool enableCamera = true)
{
var tenant = Context.User?.Claims.FirstOrDefault(x => x.Type == "tenant")?.Value;
var uid = Context.User?.Claims.FirstOrDefault(x => x.Type == "uid")?.Value;
var account = Context.User?.Claims.FirstOrDefault(x => x.Type == "account")?.Value;
var ssid = Context.User?.Claims.FirstOrDefault(x => x.Type == "ssid")?.Value;
var uname = Context.User?.Claims.FirstOrDefault(x => x.Type == "uname")?.Value;
var roleId = Context.User?.Claims.FirstOrDefault(x => x.Type == "role")?.Value;
Console.WriteLine($"{DateTime.Now}加入频道 会议号:" + roomNum);
Console.WriteLine($"{DateTime.Now}加入频道 account" + account);
Console.WriteLine($"{DateTime.Now}加入频道 tenant" + tenant);
using (var pipe = RedisHelper.Instance.StartPipe())
{
var userInfo = new ChannelUserInfo(uid, Context.ConnectionId, enableMicr, enableCamera, account, ssid);
pipe.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(tenant, roomNum), uid, userInfo.ToJsonString());
//pipe.HIncrBy(RedisKeyConstant.SessionManage.GetChannelUserCountKey(tenant), roomNum, 1);
pipe.HSet(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(uid), roomNum, 1);
pipe.EndPipe();
}
//using (var pipe = RedisHelper.Instance.StartPipe())
//{
// var userInfo = new ChannelUserInfo(uid, Context.ConnectionId, enableMicr, enableCamera, account, ssid);
// pipe.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(tenant, roomNum), uid, userInfo.ToJsonString());
// //pipe.HIncrBy(RedisKeyConstant.SessionManage.GetChannelUserCountKey(tenant), roomNum, 1);
// pipe.HSet(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(uid), roomNum, 1);
// pipe.EndPipe();
//}
await Groups.AddToGroupAsync(Context.ConnectionId, roomNum);
//await Groups.AddToGroupAsync(Context.ConnectionId, roomNum);
//await Clients.GroupExcept(roomNum, Context.ConnectionId).UserJoined(new Domain.DTOs.User.UserOutputDTO
//{
// Id = uid,
// UserName = uname,
// Account = account,
// RoleId = roleId,
// RoleName = ((RoleEnums)roleId.ToInt32()).GetDescription(),
// EnableCamera = enableCamera,
// EnableMicr = enableMicr,
// ScreenShareId = ssid,
// IsOnline = true,
//});
}
/// <summary>
/// 离开频道
/// </summary>
/// <param name="roomNum"></param>
[HubMethodName("levelChannel")]
[HubMethodName("levelChannel"), Obsolete("废弃请使用Api接口 LevelChannel")]
public async Task LevelChannel(string roomNum)
{
var tenant = Context.User?.Claims.FirstOrDefault(x => x.Type == "tenant")?.Value;
var uid = Context.User?.Claims.FirstOrDefault(x => x.Type == "uid")?.Value;
var account = Context.User?.Claims.FirstOrDefault(x => x.Type == "account")?.Value;
var ssid = Context.User?.Claims.FirstOrDefault(x => x.Type == "ssid")?.Value;
var uname = Context.User?.Claims.FirstOrDefault(x => x.Type == "uname")?.Value;
var roleId = Context.User?.Claims.FirstOrDefault(x => x.Type == "role")?.Value;
Console.WriteLine($" {DateTime.Now}离开频道 会议号:" + roomNum);
Console.WriteLine($" {DateTime.Now}离开频道 account" + account);
Console.WriteLine($" {DateTime.Now}离开频道 tenant" + tenant);
using (var pipe = RedisHelper.Instance.StartPipe())
{
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.RoomManager.GetChannelShowUserKey(tenant)], roomNum, uid, ssid);
pipe.HDel(RedisKeyConstant.SessionManage.GetChannelUserKey(tenant, roomNum), uid);
pipe.HDel(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(uid), roomNum);
pipe.EndPipe();
}
//using (var pipe = RedisHelper.Instance.StartPipe())
//{
// 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(tenant)], roomNum, uid, ssid);
// pipe.HDel(RedisKeyConstant.SessionManage.GetChannelUserKey(tenant, roomNum), uid);
// pipe.HDel(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(uid), roomNum);
// pipe.EndPipe();
//}
await Groups.RemoveFromGroupAsync(Context.ConnectionId, roomNum);
//await Clients.GroupExcept(roomNum, Context.ConnectionId).UserLeave(uid);
//await Groups.RemoveFromGroupAsync(Context.ConnectionId, roomNum);
}
/// <summary>

View File

@ -1,5 +1,6 @@
using Hangfire;
using Masuit.Tools;
using Microsoft.AspNetCore.Http.Features;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
@ -29,6 +30,13 @@ namespace WGShare.API
});
ResetRedisKey();
builder.Services.Configure<FormOptions>(options =>
{
options.ValueLengthLimit = int.MaxValue;
options.MultipartBodyLengthLimit = long.MaxValue; // If we are multipart
options.MemoryBufferThreshold = int.MaxValue;
});
builder.Services.AddControllers(options =>
{
// 全局异常捕获,无需在代码中 写 try catch
@ -122,7 +130,7 @@ namespace WGShare.API
}
while (nextCursor != 0);
var keysArr = keys.ConvertAll(x => x.Replace("wgshare:", "")).Where(x => !x.StartsWith("refresh")).Distinct().ToArray();
var keysArr = keys.ConvertAll(x => x.Replace("wgshare:", "")).Where(x => x.StartsWith("SessionManage")).Distinct().ToArray();
if (!keysArr.IsNullOrEmpty())
{
Console.WriteLine($@"删除键值:{Environment.NewLine}{string.Join(Environment.NewLine, keysArr)}");

View File

@ -15,7 +15,6 @@
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.14" />
<PackageReference Include="Hangfire.Core" Version="1.8.14" />
<PackageReference Include="Hangfire.MemoryStorage" Version="1.8.1.1" />
<PackageReference Include="MiniExcel" Version="1.34.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>

View File

@ -60,6 +60,13 @@
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Controllers.Backend.UserController.Import(Microsoft.AspNetCore.Http.IFormFile,System.String)">
<summary>
Excel 导入用户
</summary>
<param name="file"></param>
<returns></returns>
</member>
<member name="T:WGShare.API.Controllers.Frontend.HomeController">
<summary>
首页接口
@ -90,13 +97,13 @@
会议室接口
</summary>
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.SetRoomManager(System.String,System.Collections.Generic.List{System.String})">
<member name="M:WGShare.API.Controllers.Frontend.RoomController.SetRoomManager(System.String,System.String,System.String)">
<summary>
设置房间管理员
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.DelRoomManager(System.String,System.Collections.Generic.List{System.String})">
<member name="M:WGShare.API.Controllers.Frontend.RoomController.DelRoomManager(System.String,System.String,System.String)">
<summary>
取消房间管理员
</summary>
@ -104,7 +111,7 @@
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.GetUsers(System.String)">
<summary>
查询用户信息
查询房间中所有用户信息
</summary>
<returns></returns>
</member>
@ -138,13 +145,19 @@
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.Mute(System.String,System.Boolean,System.String,System.Nullable{System.Boolean})">
<member name="M:WGShare.API.Controllers.Frontend.RoomController.MuteAll(System.String,System.Boolean)">
<summary>
开闭麦
全部人开闭麦
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.CloseCamera(System.String,System.Boolean,System.String,System.Nullable{System.Boolean})">
<member name="M:WGShare.API.Controllers.Frontend.RoomController.Mute(System.String,System.Boolean,System.String)">
<summary>
单用户开闭麦
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.CloseCamera(System.String,System.Boolean,System.String)">
<summary>
开关闭摄像头
</summary>
@ -169,6 +182,22 @@
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.JoinChannel(System.String,System.Boolean,System.Boolean)">
<summary>
加入频道
</summary>
<param name="roomNum"></param>
<param name="enableMicr"></param>
<param name="enableCamera"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.LevelChannel(System.String)">
<summary>
离开频道
</summary>
<param name="roomNum"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Controllers.Frontend.RoomController.AddFile(WGShare.Domain.DTOs.File.ShareFileInputDTO)">
<summary>
分享上传文件
@ -285,6 +314,13 @@
<param name="expireInSecond">过期时间 秒</param>
<returns></returns>
</member>
<member name="M:WGShare.API.Helpers.OssHelper.UploadWithExpireTime(System.String,System.IO.MemoryStream,System.Int32)">
<summary>
流上传文件
</summary>
<param name="objectName"></param>
<param name="stream"></param>
</member>
<member name="T:WGShare.API.Helpers.RedisHelper">
<summary>
redis静态访问类
@ -344,20 +380,6 @@
<param name="roomNum">会议号</param>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.OperMicr(System.Boolean)">
<summary>
用户开闭麦
</summary>
<param name="enableMicr"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.OperCamera(System.Boolean)">
<summary>
用户开启关闭摄像头
</summary>
<param name="enableCamera"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.RefreshUserList">
<summary>
刷新用户列表
@ -383,6 +405,46 @@
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.UserJoined(WGShare.Domain.Entities.ChannelUserInfo)">
<summary>
用户加入频道回调
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.UserLeave(System.String)">
<summary>
用户退出频道回调
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.OperAllMicr(System.Boolean)">
<summary>
所有用户开闭麦
</summary>
<param name="enableMicr"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.OperMicr(WGShare.Domain.Entities.ChannelUserInfo)">
<summary>
用户关闭开启麦克风
</summary>
<param name="user"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.OperCamera(WGShare.Domain.Entities.ChannelUserInfo)">
<summary>
用户开启关闭摄像头
</summary>
<param name="user"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.ManagerRefresh(WGShare.Domain.Entities.ChannelUserInfo)">
<summary>
管理员用户信息刷新
</summary>
<param name="user"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.SessionManageHub.JoinChannel(System.String,System.Boolean,System.Boolean)">
<summary>
加入频道

View File

@ -19,7 +19,7 @@ namespace WGShare.Domain.Constant
/// <summary>
/// 在线人数
/// </summary>
public static string GetOnlineUserKey(string tenantId) => $@"te_{tenantId}:OnlieUser";
public static string GetOnlineUserKey(string tenantId) => $@"SessionManage:te_{tenantId}:OnlieUser";
/// <summary>
/// 频道用户
@ -27,36 +27,41 @@ namespace WGShare.Domain.Constant
/// <param name="tenantId"></param>
/// <param name="roomNum"></param>
/// <returns></returns>
public static string GetChannelUserKey(string tenantId, string roomNum) => $@"te_{tenantId}:ch_{roomNum}";
public static string GetChannelUserKey(string tenantId, string roomNum) => $@"SessionManage:te_{tenantId}:ch_{roomNum}";
/// <summary>
/// 用户参与频道
/// </summary>
/// <param name="uid"></param>
/// <returns></returns>
public static string GetUserJoinChannelKey(string uid) => $@"u_{uid}_join";
public static string GetUserJoinChannelKey(string uid) => $@"SessionManage:u_{uid}_join";
/// <summary>
/// 频道用户数
/// </summary>
/// <param name="tenantId"></param>
/// <returns></returns>
[Obsolete("废弃")]
public static string GetChannelUserCountKey(string tenantId) => $@"te_{tenantId}:ChannelUserCount";
}
/// <summary>
/// 房间管理
/// </summary>
public class RoomManager
{
/// <summary>
/// 获取频道全员观看对象
/// </summary>
/// <param name="tenantId"></param>
/// <param name="roomNum"></param>
/// <returns></returns>
public static string GetChannelShowUserKey(string tenantId) => $@"te_{tenantId}:room_show_user";
public static string GetChannelShowUserKey(string tenantId) => $@"SessionManage:te_{tenantId}:room_show_user";
}
/// <summary>
/// 持久化数据
/// </summary>
public class Data
{
/// <summary>
/// 获取token
/// </summary>
/// <param name="refreshToken"></param>
/// <returns></returns>
public static string GetRefreshTokenKey(string refreshToken) => $@"data:refresh:{refreshToken}";
public static string GetScreenShareIdKey => $@"data:screen_share_id";
}
}
}

View File

@ -0,0 +1,37 @@
using MiniExcelLibs.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WGShare.Domain.DTOs.User
{
public class UserExcelInputDto
{
/// <summary>
/// 用户名称
///</summary>
[ExcelColumnName("用户名称")]
public string UserName { get; set; }
/// <summary>
/// 账号
///</summary>
[ExcelColumnName("登录账号")]
public string Account { get; set; }
/// <summary>
/// 密码
///</summary>
[ExcelColumnName("登录密码")]
public string? Pwd { get; set; }
/// <summary>
///
///</summary>
[ExcelColumnName("角色")]
public string RoleId{ get; set; }
[ExcelColumnName("导入结果")]
public string ImportResult { get; set; } = string.Empty;
}
}

View File

@ -21,21 +21,6 @@ namespace WGShare.Domain.DTOs.User
public string RoleId { get; set; }
public string RoleName { get; set; }
/// <summary>
/// 是否管理员
/// </summary>
public bool IsManager { get; set; }
/// <summary>
/// 是否关闭麦克风
/// </summary>
public bool EnableMicr { get; set; }
/// <summary>
/// 是否关闭摄像头
/// </summary>
public bool EnableCamera { get; set; }
/// <summary>
/// 是否在线
/// </summary>

View File

@ -11,26 +11,7 @@ namespace WGShare.Domain.Entities
/// </summary>
public class ChannelUserInfo
{
public ChannelUserInfo()
{
}
/// <summary>
///
/// </summary>
/// <param name="uid"></param>
/// <param name="connectId"></param>
/// <param name="isMute">是否关闭麦克风,默认关</param>
/// <param name="enableCamera">是否关闭摄像头,默认关</param>
public ChannelUserInfo(string uid, string connectId, bool enableMicr, bool enableCamera, string account, string screenShareId)
{
this.UID = uid;
this.ConnectId = connectId;
this.EnableMicr = enableMicr;
this.EnableCamera = enableCamera;
this.Account = account;
this.ScreenShareId = screenShareId;
}
public string UID { get; set; }
@ -49,5 +30,13 @@ namespace WGShare.Domain.Entities
public bool EnableCamera { get; set; }
public string ScreenShareId { get; set; }
public string UserName { get; set; }
public string RoleId { get; set; }
public string RoleName { get; set; }
/// <summary>
/// 是否房间管理员
/// </summary>
public bool IsRoomManager { get; set; }
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WGShare.Domain.Entities;
namespace WGShare.Domain.Enums
{
/// <summary>
/// 角色枚举
/// </summary>
public enum RoleEnums
{
[Description("管理员")]
Admin = 1,
[Description("普通用户")]
User = 2,
}
}

View File

@ -12,6 +12,7 @@
<PackageReference Include="Masuit.Tools.Core" Version="2024.3.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" />
<PackageReference Include="MiniExcel" Version="1.34.0" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.158" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>