添加项目文件。
This commit is contained in:
249
Chat/Chat.cs
Normal file
249
Chat/Chat.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity.Data;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using StackExchange.Redis;
|
||||
using System.Diagnostics;
|
||||
using WebAppServer1.ApplicationDbContext;
|
||||
using WebAppServer1.Authentication;
|
||||
using WebAppServer1.Models;
|
||||
using WebAppServer1.Tool;
|
||||
|
||||
namespace WebAppServer1.Chat
|
||||
{
|
||||
public class Chat : Hub
|
||||
{
|
||||
|
||||
private readonly ILogger<Chat> logger;
|
||||
private readonly IConnectionMultiplexer _redis;
|
||||
private readonly AppDbContext pgSql;
|
||||
private readonly TokenService jwtService;
|
||||
|
||||
|
||||
public Chat(ILogger<Chat> _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();
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//发送已读回执
|
||||
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 userid, string message)
|
||||
{
|
||||
var receiver = await pgSql.Users.FindAsync(int.Parse(userid));
|
||||
if (receiver == null)
|
||||
{
|
||||
await Clients.Caller.SendAsync("SendPrivateMessage", false, "用户不存在", Context.UserIdentifier);
|
||||
return;
|
||||
}
|
||||
var newMesssage = new Message
|
||||
{
|
||||
SenderId = int.Parse(Context.UserIdentifier!),
|
||||
ReceiverId = receiver.Id,
|
||||
Content = message,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
MessageType = MessageType.Text,
|
||||
IsDeleted = false,
|
||||
IsRead = false
|
||||
};
|
||||
pgSql.Messages.Add(newMesssage);
|
||||
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);
|
||||
}
|
||||
|
||||
//搜索好友
|
||||
public async Task<SearchFriendsResultResponse> 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 SearchFriendsResultResponse { success = false }
|
||||
: new SearchFriendsResultResponse
|
||||
{
|
||||
success = true,
|
||||
userid = user.Id,
|
||||
username = user.Nickname
|
||||
};
|
||||
}
|
||||
|
||||
//获取用户表单测试
|
||||
public async Task<List<object>> 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<object>().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)
|
||||
{
|
||||
var exists = await pgSql.Users.AnyAsync(a => a.Username == username && a.PasswordHash == password);
|
||||
if (!exists)
|
||||
{
|
||||
await Clients.Client(Context.ConnectionId).SendAsync("LoginResult",false,"用户名或密码错误!");
|
||||
return;
|
||||
}
|
||||
var user = await pgSql.Users.FirstOrDefaultAsync(a => a.Username == username);
|
||||
if (user == null) { return; }
|
||||
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}");
|
||||
}
|
||||
//新用户注册
|
||||
public async Task Register()
|
||||
{
|
||||
|
||||
var newUser = new User
|
||||
{
|
||||
Username = "user_" + Guid.NewGuid().ToString("N").Substring(0, 8),
|
||||
Nickname = GenerateTool.GenerateRandomNickname(),
|
||||
PasswordHash = GenerateTool.GeneratePassword(),
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
//统计在线人数
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user