diff --git a/Chat/Chat.cs b/Chat/Chat.cs index 478990a..eba67cb 100644 --- a/Chat/Chat.cs +++ b/Chat/Chat.cs @@ -1,7 +1,9 @@ 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; @@ -31,14 +33,34 @@ namespace WebAppServer1.Chat //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(); @@ -52,7 +74,26 @@ namespace WebAppServer1.Chat 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); } @@ -94,30 +135,76 @@ namespace WebAppServer1.Chat 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; }; + if (update == null) return; + update.IsRead = true; pgSql.Messages.Update(update); await pgSql.SaveChangesAsync(); - await Clients.User(update.SenderId.ToString()).SendAsync("SendReadReceipt",messageId); + + // 通知消息发送者该消息已读 + await Clients.User(update.SenderId.ToString()) + .SendAsync("SendReadReceipt", messageId); } + //发送私聊消息 - [Authorize] - public async Task SendPrivateMessage(string userid, string message) + [Authorize] + public async Task SendPrivateMessage(string friendId, string message) { - var receiver = await pgSql.Users.FindAsync(int.Parse(userid)); - if (receiver == null) + + 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", false, "用户不存在", Context.UserIdentifier); + await Clients.Caller.SendAsync("SendPrivateMessage", new ChatMessageDto + { + IsMine = true, + Message = "双方不是朋友关系,暂时无法发送消息,请添加好友后再发送消息!", + SenderId = intUserId, + ReceiverId = receiver.Id + }); return; } - var newMesssage = new Message + + var newMessage = new Message { - SenderId = int.Parse(Context.UserIdentifier!), + SenderId = intUserId, ReceiverId = receiver.Id, Content = message, CreatedAt = DateTime.UtcNow, @@ -125,27 +212,85 @@ namespace WebAppServer1.Chat IsDeleted = false, IsRead = false }; - pgSql.Messages.Add(newMesssage); + pgSql.Messages.Add(newMessage); await pgSql.SaveChangesAsync(); - await Clients.User(userid).SendAsync("SendPrivateMessage", true, message,Context.UserIdentifier,newMesssage.Id); - await Clients.Caller.SendAsync("SendPrivateMessage", false, message, Context.UserIdentifier,newMesssage.Id); + + // 发给接收者 + 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 user = await pgSql.Users.FindAsync(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 = int.Parse(Context.UserIdentifier!), + UserId = senderId, FriendId = userId, CreatedAt = DateTime.UtcNow, - Status = FriendStatus.Pending + 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) { diff --git a/Models/ResultResponse.cs b/Models/ResultResponse.cs index 7adc85d..886d6fd 100644 --- a/Models/ResultResponse.cs +++ b/Models/ResultResponse.cs @@ -33,4 +33,44 @@ namespace WebAppServer1.Models [Key("Success")] public bool Success { get; set; } } + + [MessagePackObject] + public class FriendsResultResponse + { + [Key("userid")] + public int Id { get; set; } + [Key("nickname")] + public string Nickname { get; set; } + [Key("username")] + public string Username { get; set; } + [Key("signature")] + public string Signature { get; set; } + [Key("isonline")] + public bool IsOnline { get; set; } + [Key("avatarurl")] + public string AvatarUrl { get; set; } + } + + [MessagePackObject] + public class ChatMessageDto + { + [Key("MessageId")] + public int MessageId { get; set; } + [Key("Message")] + public string Message { get; set; } + [Key("IsRead")] + public bool IsRead { get; set; } + [Key("SenderId")] + public int SenderId { get; set; } + [Key("ReceiverId")] + public int? ReceiverId { get; set; } + [Key("IsMine")] + public bool IsMine { get; set; } // true 表示自己发的 + [Key("Nickname")] + public string Nickname { get; set; } + [Key("AvatarUrl")] + public string AvatarUrl { get; set; } + } + + }