// using Masuit.Tools.DateTimeExt; namespace SafeCampus.System; /// /// /// public class SessionService : DbRepository, ISessionService { private readonly ISimpleCacheService _simpleCacheService; private readonly IEventPublisher _eventPublisher; public SessionService(ISimpleCacheService simpleCacheService, IEventPublisher eventPublisher) { _simpleCacheService = simpleCacheService; _eventPublisher = eventPublisher; } /// public async Task> PageB(SessionPageInput input) { //获取b端token列表 var bTokenInfoDic = GetTokenDicFromRedis(); //获取用户ID列表 var userIds = bTokenInfoDic.Keys.Select(it => it.ToLong()).ToList(); var query = Context.Queryable().Where(it => userIds.Contains(it.Id))//根据ID查询 .WhereIF(!string.IsNullOrEmpty(input.Name), it => it.Name.Contains(input.Name))//根据姓名查询 .WhereIF(!string.IsNullOrEmpty(input.Account), it => it.Account.Contains(input.Account))//根据账号查询 .WhereIF(!string.IsNullOrEmpty(input.LatestLoginIp), it => it.LatestLoginIp.Contains(input.LatestLoginIp))//根据IP查询 .OrderBy(it => it.LatestLoginTime, OrderByType.Desc).Select().Mapper(it => { var tokenInfos = bTokenInfoDic[it.Id.ToString()];//获取用户token信息 GetTokenInfos(ref tokenInfos, LoginClientTypeEnum.B);//获取剩余时间 it.TokenCount = tokenInfos.Count;//令牌数量 it.TokenSignList = tokenInfos;//令牌列表 //如果有mqtt客户端ID就是在线 it.OnlineStatus = tokenInfos.Any(it => it.ClientIds.Count > 0) ? SysDictConst.ONLINE_STATUS_ONLINE : SysDictConst.ONLINE_STATUS_OFFLINE; }); var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页 pageInfo.List.OrderByDescending(it => it.TokenCount); return pageInfo; } /// public async Task> PageC(SessionPageInput input) { return new SqlSugarPagedList { PageNum = 1, PageSize = 20, Total = 0, Pages = 1, HasNextPages = false }; } /// public SessionAnalysisOutPut Analysis() { var tokenDic = GetTokenDicFromRedis();//redisToken会话字典信息 var tokenInfosList = tokenDic.Values.ToList();//端token列表 var dicB = new Dictionary>(); var dicC = new Dictionary>(); var onLineCount = 0; foreach (var token in tokenDic) { var b = token.Value.Where(it => it.LoginClientType == LoginClientTypeEnum.B).ToList();//获取该用户B端token var c = token.Value.Where(it => it.LoginClientType == LoginClientTypeEnum.C).ToList();//获取该用户C端token if (b.Count > 0) dicB.Add(token.Key, b); if (c.Count > 0) dicC.Add(token.Key, c); var count = token.Value.Count(it => it.ClientIds.Count > 0);//计算在线用户 onLineCount += count; } var tokenB = dicB.Values.ToList();//b端token列表 var tokenC = dicC.Values.ToList();//c端token列表 int maxCountB = 0, maxCountC = 0; if (tokenB.Count > 0) maxCountB = tokenB.OrderByDescending(it => it.Count).Take(1).First().Count;//b端最大会话数 if (tokenC.Count > 0) maxCountC = tokenC.OrderByDescending(it => it.Count).Take(1).First().Count;//C端最大会话数 return new SessionAnalysisOutPut { OnLineCount = onLineCount, CurrentSessionTotalCount = tokenB.Count + tokenC.Count, MaxTokenCount = maxCountB > maxCountC ? maxCountB : maxCountC, ProportionOfBAndC = $"{tokenB.Count}/{tokenC.Count}" }; } /// public async Task ExitSession(BaseIdInput input) { var userId = input.Id.ToString(); //token列表 var tokenInfos = _simpleCacheService.HashGetOne>(CacheConst.CACHE_USER_TOKEN, userId); //从列表中删除 _simpleCacheService.HashDel>(CacheConst.CACHE_USER_TOKEN, userId); await NoticeUserLoginOut(userId, tokenInfos); } /// public async Task ExitToken(ExitTokenInput input) { var userId = input.Id.ToString(); //获取该用户的token信息 var tokenInfos = _simpleCacheService.HashGetOne>(CacheConst.CACHE_USER_TOKEN, userId); //当前需要踢掉用户的token var deleteTokens = tokenInfos.Where(it => input.Tokens.Contains(it.Token)).ToList(); //踢掉包含token列表的token信息 tokenInfos = tokenInfos.Where(it => !input.Tokens.Contains(it.Token)).ToList(); if (tokenInfos.Count > 0) _simpleCacheService.HashAdd(CacheConst.CACHE_USER_TOKEN, userId, tokenInfos);//如果还有token则更新token else _simpleCacheService.HashDel>(CacheConst.CACHE_USER_TOKEN, userId);//否则直接删除key await NoticeUserLoginOut(userId, deleteTokens); } #region 方法 /// /// 获取redis中token信息列表 /// /// public Dictionary> GetTokenDicFromRedis() { var clockSkew = App.GetConfig("JWTSettings:ClockSkew");//获取过期时间容错值(秒) //redis获取token信息hash集合,并转成字典 var bTokenDic = _simpleCacheService.HashGetAll>(CacheConst.CACHE_USER_TOKEN).ToDictionary(u => u.Key, u => u.Value); if (bTokenDic != null) { bTokenDic.ForEach(it => { var tokens = it.Value.Where(it => it.TokenTimeout.AddSeconds(clockSkew) > DateTime.Now).ToList();//去掉登录超时的 if (tokens.Count == 0) { //表示都过期了 bTokenDic.Remove(it.Key); } else { bTokenDic[it.Key] = tokens;//重新赋值token } }); if (bTokenDic.Count > 0) { _simpleCacheService.HashSet(CacheConst.CACHE_USER_TOKEN, bTokenDic);//如果还有token则更新token } else { _simpleCacheService.Remove(CacheConst.CACHE_USER_TOKEN);//否则直接删除key } return bTokenDic; } return new Dictionary>(); } /// /// 获取token剩余时间信息 /// /// token列表 /// 登录类型 public void GetTokenInfos(ref List tokenInfos, LoginClientTypeEnum loginClientType) { tokenInfos = tokenInfos.Where(it => it.LoginClientType == loginClientType).ToList(); tokenInfos.ForEach(it => { var now = DateTime.Now; it.TokenRemain = now.GetDiffTime(it.TokenTimeout);//获取时间差 var tokenSecond = it.TokenTimeout.AddMinutes(-it.Expire).ConvertDateTimeToLong();//颁发时间转为时间戳 var timeoutSecond = it.TokenTimeout.ConvertDateTimeToLong();//过期时间转为时间戳 var tokenRemainPercent = 1 - (now.ConvertDateTimeToLong() - tokenSecond) * 1.0 / (timeoutSecond - tokenSecond);//求百分比,用现在时间-token颁布时间除以超时时间-token颁布时间 it.TokenRemainPercent = tokenRemainPercent; }); } /// /// 通知用户下线 /// /// private async Task NoticeUserLoginOut(string userId, List tokenInfos) { await _eventPublisher.PublishAsync(EventSubscriberConst.USER_LOGIN_OUT, new UserLoginOutEvent { Message = "您已被强制下线!", TokenInfos = tokenInfos, UserId = userId });//通知用户下线 } #endregion 方法 }