- 将菜单实体的 ID 类型从 Guid 改为 long,并配置为自增主键 - 添加菜单创建、删除、树形结构构建等完整的 CRUD 操作支持 - 为文件上传相关端点添加 file:upload 权限验证 - 为文件操作端点添加 file:read 和 file:write 权限控制 - 为通知功能添加 notification:read 权限限制 - 实现 BuildFlow 按钮执行的权限检查机制 - 在 IM 模块中集成 Redis 未读计数器优化性能 - 更新用户主页路径从 /workspace 到 /dashboard/workspace - 添加 SignalR Hub 授权和 WebSocket 连接安全保护 - 新增平台测试项目并完善按钮权限测试用例
51 lines
2.0 KiB
C#
51 lines
2.0 KiB
C#
using IM.Application.Chat.DTOs;
|
||
using IM.Application.Chat.Queries;
|
||
using IM.Domain.Common;
|
||
using IM.Infrastructure.Persistence;
|
||
using MediatR;
|
||
|
||
namespace IM.Application.Chat.Handlers;
|
||
|
||
/// <summary>
|
||
/// 未读计数查询。读扩散热路径:Redis 优先,未命中回退 PostgreSQL 冷备。
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 兼容策略:Redis 命中的会话用 Redis 值(权威);Redis 未命中的会话(老数据/降级期间写入)回退 PG 的 UnreadCount。
|
||
/// 二者合并去重,最终结果保证不丢未读。
|
||
/// </remarks>
|
||
public class GetUnreadCountQueryHandler(ImDbContext db, IUnreadCounter unreadCounter) : IRequestHandler<GetUnreadCountQuery, UnreadCountsDto>
|
||
{
|
||
public async Task<UnreadCountsDto> Handle(GetUnreadCountQuery request, CancellationToken ct)
|
||
{
|
||
// 先从 PG 取用户参与的所有会话及其冷备未读数(也作为 Redis 全故障时的兜底数据源)。
|
||
// 注意不能用 p.UnreadCount > 0 预过滤:发送链路已把未读累加移到 Redis,PG 冷备可能仍为 0。
|
||
var participants = await db.ConversationParticipants
|
||
.Where(p => p.UserId == request.UserId)
|
||
.Select(p => new { p.ConversationId, p.UnreadCount })
|
||
.ToListAsync(ct);
|
||
|
||
if (participants.Count == 0)
|
||
{
|
||
return new UnreadCountsDto([], 0);
|
||
}
|
||
|
||
var pgUnread = participants.ToDictionary(p => p.ConversationId, p => p.UnreadCount);
|
||
|
||
// 批量查 Redis 热数据
|
||
var redisUnread = await unreadCounter.GetByUserAsync(
|
||
request.UserId,
|
||
pgUnread.Keys,
|
||
ct);
|
||
|
||
// 合并:Redis 命中用 Redis 值,未命中回退 PG
|
||
var items = pgUnread.Keys
|
||
.Select(convId => new UnreadCountDto(
|
||
convId,
|
||
redisUnread.TryGetValue(convId, out var redisValue) ? redisValue : pgUnread[convId]))
|
||
.Where(i => i.UnreadCount > 0)
|
||
.ToList();
|
||
|
||
return new UnreadCountsDto(items, items.Sum(i => i.UnreadCount));
|
||
}
|
||
}
|