first commit
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using F9WebAiTest.Api.Hubs;
|
||||
using F9WebAiTest.Application.Services;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace F9WebAiTest.Api.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 业务状态变更事件的 SignalR 推送处理器。
|
||||
/// 业务服务发布 BusinessChangedEvent 后,推送给所有在线客户端,
|
||||
/// 各端监听 "BusinessChanged" 后刷新已打开的相关页面,实现多端实时同步。
|
||||
/// </summary>
|
||||
public class BusinessChangedEventHandler : INotificationHandler<BusinessChangedEvent>
|
||||
{
|
||||
private readonly IHubContext<NotificationHub> _hubContext;
|
||||
|
||||
public BusinessChangedEventHandler(IHubContext<NotificationHub> hubContext)
|
||||
=> _hubContext = hubContext;
|
||||
|
||||
public Task Handle(BusinessChangedEvent e, CancellationToken ct)
|
||||
=> _hubContext.Clients.All.SendAsync("BusinessChanged", e, ct);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// 已移除:消息投递不再使用后台服务(BackgroundService)与轮询。
|
||||
//
|
||||
// 现在的投递方式(即时推送):
|
||||
// CreateNotificationCommandHandler(F9WebAiTest.Application/Services/Notice/NotificationMediatR.cs)
|
||||
// 在消息创建后立即:
|
||||
// 1. 确定接收人(ForceReceivers 精确送达,否则按消息类型订阅关系广播);
|
||||
// 2. 写入 NotificationReceiver(MessageId + UserId 幂等);
|
||||
// 3. 通过 INotificationPusher(实现在 F9WebAiTest.Api/Services/NotificationPusher.cs)经 SignalR 直接推送。
|
||||
//
|
||||
// 本文件已无任何代码,可直接删除。
|
||||
@@ -0,0 +1,45 @@
|
||||
using F9WebAiTest.Api.Hubs;
|
||||
using F9WebAiTest.Application.Dtos.Notice;
|
||||
using F9WebAiTest.Application.Services.Notice;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace F9WebAiTest.Api.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 消息实时推送器实现:基于 SignalR 的 IHubContext 直接推送。
|
||||
/// 无后台队列、无轮询——消息创建时同步完成投递与推送。
|
||||
///
|
||||
/// 在线判定:OnlineUserRegistry(Hub 连接/断开时登记的内存表)。
|
||||
/// 之所以需要显式判定而不能依赖推送异常:SignalR 对"无连接的 Clients.User 调用"是静默成功的,
|
||||
/// 不判定的话离线用户会被误记为推送成功。
|
||||
///
|
||||
/// 用户标识:由 NotificationUserIdProvider 统一取 JWT 的 "id" 声明,
|
||||
/// 因此 Clients.User(userId) 可精准命中该用户的所有在线连接(支持多端同时在线)。
|
||||
/// </summary>
|
||||
public class NotificationPusher : INotificationPusher
|
||||
{
|
||||
private readonly IHubContext<NotificationHub> _hubContext;
|
||||
|
||||
public NotificationPusher(IHubContext<NotificationHub> hubContext)
|
||||
{
|
||||
_hubContext = hubContext;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsOnline(long userId) => OnlineUserRegistry.IsOnline(userId);
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> PushNewMessageAsync(long userId, NotificationMessageDto message, CancellationToken ct = default)
|
||||
{
|
||||
// 离线用户:不推送(消息已持久化,上线后拉取兜底),返回 false 由调用方标记 IsOffline
|
||||
if (!OnlineUserRegistry.IsOnline(userId)) return false;
|
||||
|
||||
await _hubContext.Clients.User(userId.ToString()).SendAsync("ReceiveNotification", message, ct);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task PushUnreadCountAsync(long userId, int unreadCount, int todoCount, CancellationToken ct = default)
|
||||
=> _hubContext.Clients.User(userId.ToString())
|
||||
.SendAsync("UnreadCountChanged", new { unreadCount, todoCount }, ct);
|
||||
}
|
||||
Reference in New Issue
Block a user