using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity.Data; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using StackExchange.Redis; using System.Diagnostics; using System.Security.Cryptography.Xml; using WebAppServer1.ApplicationDbContext; using WebAppServer1.Authentication; using WebAppServer1.Models; using WebAppServer1.Tool; namespace WebAppServer1.Chat { public class Chat : Hub { private readonly ILogger logger; private readonly IConnectionMultiplexer _redis; private readonly AppDbContext pgSql; private readonly TokenService jwtService; public Chat(ILogger _logger, IConnectionMultiplexer redis, AppDbContext _pgsql,TokenService _jwtService) { logger = _logger; _redis = redis; pgSql = _pgsql; jwtService = _jwtService; } //wss子端点API //在线事件 public override async Task OnConnectedAsync() { var db = _redis.GetDatabase(); await db.SetAddAsync("AllConnections", Context.ConnectionId); await BroadcastOnlineCount(); Console.WriteLine("在线id:"+Context.UserIdentifier); if (Context.UserIdentifier != null) { int userId = int.Parse(Context.UserIdentifier!); var update = await pgSql.Users.FindAsync(userId); if (update != null) { update.IsOnline = true; pgSql.Update(update); await pgSql.SaveChangesAsync(); } List friends = await pgSql.Friends.Where(f => f.Status == FriendStatus.Accepted && (f.UserId == userId || f.FriendId == userId)).Select (f => f.UserId == userId ? f.FriendId : f.UserId).ToListAsync(); var friendIds = friends.Select(id => id.ToString()).ToList(); await Clients.Users(friendIds).SendAsync("UserStatusChanged", userId, true); } await base.OnConnectedAsync(); } //掉线事件 public override async Task OnDisconnectedAsync(Exception? exception) { var db = _redis.GetDatabase(); await db.SetRemoveAsync("AllConnections", Context.ConnectionId); // 遍历所有群组,移除该连接 var server = _redis.GetServer(_redis.GetEndPoints().First()); foreach (var key in server.Keys(pattern: "Group:*")) { await db.SetRemoveAsync(key, Context.ConnectionId); var groupName = key.ToString().Replace("Group:", ""); await BroadcastGroupCount(groupName); } await BroadcastOnlineCount(); Console.WriteLine("掉线id:" + Context.UserIdentifier); if (Context.UserIdentifier != null) { int userId = int.Parse(Context.UserIdentifier!); var update = await pgSql.Users.FindAsync(userId); if (update != null) { update.IsOnline = false; pgSql.Update(update); await pgSql.SaveChangesAsync(); } List friends = await pgSql.Friends.Where(f => f.Status == FriendStatus.Accepted && (f.UserId == userId || f.FriendId == userId)).Select (f => f.UserId == userId ? f.FriendId : f.UserId).ToListAsync(); var friendIds = friends.Select(id => id.ToString()).ToList(); await Clients.Users(friendIds).SendAsync("UserStatusChanged", userId, false); } await base.OnDisconnectedAsync(exception); } //简单广播消息 [Authorize] public async Task SendMessage(string user, string message) { logger.LogWarning("广播消息"); //测试发送 var exuser = Context.User?.Identity?.Name ?? "匿名"; await Clients.All.SendAsync("ReceiveMessage", exuser, message); } //群聊分组消息 public async Task JoinGroup(string groupName) { var db = _redis.GetDatabase(); await Groups.AddToGroupAsync(Context.ConnectionId, groupName); await db.SetAddAsync($"Group:{groupName}", Context.ConnectionId); await BroadcastGroupCount(groupName); logger.LogWarning($"用户: {Context.ConnectionId}加入了{groupName}群组!"); await Clients.Group(groupName).SendAsync("ReceiveMessage", groupName, "系统", $"{Context.ConnectionId} 加入了群组"); } public async Task LeaveGroup(string groupName) { var db = _redis.GetDatabase(); await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName); await db.SetRemoveAsync($"Group:{groupName}", Context.ConnectionId); await BroadcastGroupCount(groupName); logger.LogInformation($"用户{Context.ConnectionId}---离开了---{groupName}群组"); await Clients.Group(groupName).SendAsync("ReceiveMessage",groupName, "系统", $"{Context.ConnectionId} 离开了群聊 {groupName}"); } [Authorize] public async Task SendMessageToGroup(string groupName, string user, string message) { logger.LogInformation($"用户{user}发来的的消息:{message}"); await Clients.Group(groupName).SendAsync("ReceiveMessage", groupName, user, message); } //获取聊天记录 [Authorize] public async Task> GetChatRecord(int friendId) { var exfriendId = await pgSql.Users.FindAsync(friendId); if (exfriendId == null) return new List(); //if (Context.UserIdentifier == null) var userId = int.Parse(Context.UserIdentifier!); return await pgSql.Messages .Where(a => (a.SenderId == userId && a.ReceiverId == friendId) || (a.SenderId == friendId && a.ReceiverId == userId)) .OrderBy(f => f.Id) .Select(f => new ChatMessageDto { MessageId = f.Id, Message = f.Content, IsRead = f.IsRead, SenderId = f.SenderId, ReceiverId = f.ReceiverId, IsMine = f.SenderId == userId }) .ToListAsync(); } //发送已读回执 public async Task SendReadReceipt(int messageId) { var update = await pgSql.Messages.FindAsync(messageId); if (update == null) return; update.IsRead = true; pgSql.Messages.Update(update); await pgSql.SaveChangesAsync(); // 通知消息发送者该消息已读 await Clients.User(update.SenderId.ToString()) .SendAsync("SendReadReceipt", messageId); } //发送私聊消息 [Authorize] public async Task SendPrivateMessage(string friendId, string message) { int intFriendId = int.Parse(friendId); int intUserId = int.Parse(Context.UserIdentifier!); var receiver = await pgSql.Users.FindAsync(intFriendId); if (receiver == null) return; var sender = await pgSql.Users.FindAsync(intUserId); if (sender == null) return; bool isfriend = await pgSql.Friends.Where (a => (a.UserId == intUserId && a.FriendId == intFriendId &&a.Status == FriendStatus.Accepted) || (a.UserId == intFriendId && a.FriendId == intUserId && a.Status == FriendStatus.Accepted)).AnyAsync(); if (!isfriend) { await Clients.Caller.SendAsync("SendPrivateMessage", new ChatMessageDto { IsMine = true, Message = "双方不是朋友关系,暂时无法发送消息,请添加好友后再发送消息!", SenderId = intUserId, ReceiverId = receiver.Id }); return; } var newMessage = new Message { SenderId = intUserId, ReceiverId = receiver.Id, Content = message, CreatedAt = DateTime.UtcNow, MessageType = MessageType.Text, IsDeleted = false, IsRead = false }; pgSql.Messages.Add(newMessage); await pgSql.SaveChangesAsync(); // 发给接收者 await Clients.User(friendId).SendAsync("SendPrivateMessage",new ChatMessageDto { IsMine = false, Message = message, SenderId = intUserId, ReceiverId = receiver.Id, MessageId = newMessage.Id, Nickname = sender.Nickname, AvatarUrl = sender.AvatarUrl, }); // 同时回给发送者,保证前端立即显示 await Clients.Caller.SendAsync("SendPrivateMessage", new ChatMessageDto { IsMine = true, Message = message, SenderId = int.Parse(Context.UserIdentifier!), ReceiverId = receiver.Id, MessageId = newMessage.Id, Nickname = receiver.Nickname, AvatarUrl = receiver.AvatarUrl }); } //添加好友申请 public async Task AddFriend(int userId) { var senderId = int.Parse(Context.UserIdentifier!); var exuser = await pgSql.Friends.Where(a => a.UserId == userId && a.FriendId == senderId || (a.FriendId == userId && a.UserId == senderId)) .AnyAsync(); Console.WriteLine("测试结果:"+exuser); if (exuser) return false; pgSql.Friends.Add(new Friend { UserId = senderId, FriendId = userId, CreatedAt = DateTime.UtcNow, Status = FriendStatus.Accepted }); await pgSql.SaveChangesAsync(); return true; } //获取好友列表 public async Task> GetFriendsAsync(int userId) { var friends = await pgSql.Friends .Where(f => f.Status == FriendStatus.Accepted && (f.UserId == userId || f.FriendId == userId)) .Select(f => f.UserId == userId ? new FriendsResultResponse { Id = f.FriendUser.Id, Nickname = f.FriendUser.Nickname, Username = f.FriendUser.Username, Signature = f.FriendUser.Signature, AvatarUrl = f.FriendUser.AvatarUrl, IsOnline = f.FriendUser.IsOnline } : new FriendsResultResponse { Id = f.User.Id, Nickname = f.User.Nickname, Username = f.User.Username, Signature = f.User.Signature, AvatarUrl = f.User.AvatarUrl, IsOnline = f.User.IsOnline }) .ToListAsync(); return friends; } //搜索好友 public async Task SearchFriends(string username) { User? user = null; if (int.TryParse(username, out int userId)) { user = await pgSql.Users.FindAsync(userId); Console.WriteLine("按 ID 查询: " + userId); } if (user == null) { user = await pgSql.Users.FirstOrDefaultAsync(a => a.Username == username); } return user == null ? new { success = false } : new { success = true, userid = user.Id, username = user.Username, nickname = user.Nickname, avatarurl = user.AvatarUrl, signature = user.Signature, isonline = user.IsOnline }; } //获取用户表单测试 public async Task> GetFormData() { var users = await pgSql.Users .Select(u => new { Id = u.Id, Name = u.Username, Password = u.PasswordHash, CreatedDate = u.CreatedAt, LastModifiedDate = u.LastActive }) .ToListAsync(); return users.Cast().ToList(); } //刷新Token // 刷新 Token public async Task RefreshAccessToken(string refreshToken) { var token = await pgSql.Tokens.FirstOrDefaultAsync(t => t.RefreshToken == refreshToken); if (token == null || token.IsRevoked || token.ExpiresAt < DateTime.UtcNow) { await Clients.Caller.SendAsync("RefreshFailed", "Refresh token invalid or expired"); return; } var newAccessToken = jwtService.GenerateAccessToken(token.UserName, token.UserId); var newRefreshToken = await jwtService.GenerateRefreshToken(token.UserId, token.UserName); token.IsRevoked = true; await pgSql.SaveChangesAsync(); await Clients.Caller.SendAsync("ReceiveNewAccessToken", newAccessToken, newRefreshToken); } //登录认证 public async Task LoginAuthentication(string username, string password, string ua) { var user = await pgSql.Users.FirstOrDefaultAsync(a => a.Username == username && a.PasswordHash == password); if (user == null) { //await Clients.Client(Context.ConnectionId).SendAsync("LoginResult",false,"用户名或密码错误!"); return new LoginResultResponse { Success = false }; } if (user == null) { return new LoginResultResponse { Success = false }; } var accessToken = jwtService.GenerateAccessToken(user.Username,user.Id); var refreshToken = await jwtService.GenerateRefreshToken(user.Id, username); //await Clients.Client(Context.ConnectionId).SendAsync("LoginResult", true, accessToken, refreshToken); logger.LogInformation($"用户:{username}正在进行登录认证!密码:{password}===accessToken:{accessToken}"); var ip = Context.GetHttpContext()?.Connection?.RemoteIpAddress?.ToString(); if (ip == null ) { return new LoginResultResponse { Success = false }; } pgSql.LoginRecords.Add(new LoginRecord { UserId = user.Id, LoginTime = DateTime.UtcNow, IpAddress = ip, DeviceInfo = ua, IsSuccess = true }); await pgSql.SaveChangesAsync(); return new LoginResultResponse { Success = true, AccessToken = accessToken, RefreshToken = refreshToken, Nickname = user.Nickname, Id = user.Id, IsOnline = true, AvatarUrl = user.AvatarUrl, Signature = user.Signature }; } //新用户注册 public async Task Register() { var newUser = new User { Username = "user_" + Guid.NewGuid().ToString("N").Substring(0, 8), Nickname = GenerateTool.GenerateRandomNickname(), PasswordHash = GenerateTool.GeneratePassword(), Signature = GenerateTool.GenerateRandomSignature(), AvatarUrl = GenerateTool.GenerateRandomAvatarUrl(), CreatedAt = DateTime.UtcNow, LastActive = DateTime.UtcNow }; pgSql.Add(newUser); await pgSql.SaveChangesAsync(); logger.LogInformation($"新用户:{newUser.Username}正在进行登录注册操作!密码:{newUser.Nickname}"); return new { Username = newUser.Username, Password = newUser.PasswordHash, Success = true }; } //统计在线人数 private async Task BroadcastOnlineCount() { var db = _redis.GetDatabase(); var count = await db.SetLengthAsync("AllConnections"); await Clients.All.SendAsync("OnlineCount", count); } //统计群组在线人数 private async Task BroadcastGroupCount(string groupName) { var db = _redis.GetDatabase(); var count = await db.SetLengthAsync($"Group:{groupName}"); await Clients.Group(groupName).SendAsync("GroupCount", groupName, count); } } }