Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc6acc832d | ||
|
|
cf25f3ed6a | ||
|
|
ac264e0c0a | ||
|
|
50ebb96de9 |
245
Chat/Chat.cs
245
Chat/Chat.cs
@@ -1,9 +1,12 @@
|
||||
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;
|
||||
@@ -30,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<int> 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,6 +75,25 @@ namespace WebAppServer1.Chat
|
||||
}
|
||||
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<int> 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);
|
||||
}
|
||||
|
||||
@@ -93,30 +135,76 @@ namespace WebAppServer1.Chat
|
||||
await Clients.Group(groupName).SendAsync("ReceiveMessage", groupName, user, message);
|
||||
}
|
||||
|
||||
//获取聊天记录
|
||||
[Authorize]
|
||||
public async Task<List<ChatMessageDto>> GetChatRecord(int friendId)
|
||||
{
|
||||
var exfriendId = await pgSql.Users.FindAsync(friendId);
|
||||
if (exfriendId == null) return new List<ChatMessageDto>();
|
||||
//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)
|
||||
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,
|
||||
@@ -124,14 +212,87 @@ 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<bool> 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<List<FriendsResultResponse>> 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<SearchFriendsResultResponse> SearchFriends(string username)
|
||||
public async Task<object> SearchFriends(string username)
|
||||
{
|
||||
User? user = null;
|
||||
|
||||
@@ -145,12 +306,16 @@ namespace WebAppServer1.Chat
|
||||
user = await pgSql.Users.FirstOrDefaultAsync(a => a.Username == username);
|
||||
}
|
||||
return user == null
|
||||
? new SearchFriendsResultResponse { success = false }
|
||||
: new SearchFriendsResultResponse
|
||||
? new { success = false }
|
||||
: new
|
||||
{
|
||||
success = true,
|
||||
userid = user.Id,
|
||||
username = user.Nickname
|
||||
username = user.Username,
|
||||
nickname = user.Nickname,
|
||||
avatarurl = user.AvatarUrl,
|
||||
signature = user.Signature,
|
||||
isonline = user.IsOnline
|
||||
};
|
||||
}
|
||||
|
||||
@@ -193,38 +358,64 @@ namespace WebAppServer1.Chat
|
||||
}
|
||||
|
||||
//登录认证
|
||||
public async Task LoginAuthentication(string username, string password)
|
||||
public async Task<LoginResultResponse> LoginAuthentication(string username, string password, string ua)
|
||||
{
|
||||
var exists = await pgSql.Users.AnyAsync(a => a.Username == username && a.PasswordHash == password);
|
||||
if (!exists)
|
||||
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;
|
||||
//await Clients.Client(Context.ConnectionId).SendAsync("LoginResult",false,"用户名或密码错误!");
|
||||
return new LoginResultResponse { Success = false };
|
||||
}
|
||||
var user = await pgSql.Users.FirstOrDefaultAsync(a => a.Username == username);
|
||||
if (user == null) { return; }
|
||||
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);
|
||||
//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()
|
||||
public async Task<object> 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}");
|
||||
await Clients.Client(Context.ConnectionId).SendAsync("RegisterResult", true,"恭喜注册成功!");
|
||||
await LoginAuthentication(newUser.Username,newUser.PasswordHash);
|
||||
return new
|
||||
{
|
||||
Username = newUser.Username,
|
||||
Password = newUser.PasswordHash,
|
||||
Success = true
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,69 @@ namespace WebAppServer1.Models
|
||||
[Key("success")]
|
||||
public bool success { get; set; }
|
||||
[Key("username")]
|
||||
public string username { get; set; }
|
||||
public string username { get; set; } = string.Empty;
|
||||
[Key("userid")]
|
||||
public int userid { get; set; }
|
||||
};
|
||||
|
||||
[MessagePackObject]
|
||||
public class LoginResultResponse
|
||||
{
|
||||
[Key("Nickname")]
|
||||
public string Nickname { get; set; } = string.Empty;
|
||||
[Key("Id")]
|
||||
public int Id { get; set; }
|
||||
[Key("AvatarUrl")]
|
||||
public string AvatarUrl { get; set; } = string.Empty;
|
||||
[Key("Signature")]
|
||||
public string Signature { get; set; } = string.Empty;
|
||||
[Key("IsOnline")]
|
||||
public bool IsOnline { get; set; }
|
||||
[Key("AccessToken")]
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
[Key("RefreshToken")]
|
||||
public string RefreshToken { get; set; } = string.Empty;
|
||||
[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; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ using WebAppServer1.ApplicationDbContext;
|
||||
using WebAppServer1.Authentication;
|
||||
using WebAppServer1.Chat;
|
||||
|
||||
|
||||
//进度为简单聊天存储,私聊搜索用户等
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
@@ -41,5 +41,30 @@ namespace WebAppServer1.Tool
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public static string GenerateRandomSignature()
|
||||
{
|
||||
string[] part1 = { "自由的", "快乐的", "孤独的", "勇敢的", "神秘的" };
|
||||
string[] part2 = { "小鸟", "星星", "花朵", "少年", "旅人" };
|
||||
string[] part3 = { "在唱歌", "在飞翔", "在微笑", "在流浪", "在思考" };
|
||||
|
||||
var random = new Random();
|
||||
string nickname = part1[random.Next(part1.Length)]
|
||||
+ part2[random.Next(part2.Length)]
|
||||
+ part3[random.Next(part3.Length)];
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public static string GenerateRandomAvatarUrl()
|
||||
{
|
||||
string[] part1 = { "https://auth.zotv.ru/webapp/"};
|
||||
string[] part2 = { "8111", "9666", "6222", "2501", "4974", "3322" };
|
||||
string[] part3 = { ".webp" };
|
||||
|
||||
var random = new Random();
|
||||
string nickname = part1[random.Next(part1.Length)]
|
||||
+ part2[random.Next(part2.Length)]
|
||||
+ part3[random.Next(part3.Length)];
|
||||
return nickname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user