50 lines
2.2 KiB
C#
50 lines
2.2 KiB
C#
using Microsoft.AspNetCore.SignalR;
|
|
using ZB.MOM.WW.OtOpcUa.Admin.Hubs;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Admin.Services;
|
|
|
|
/// <summary>
|
|
/// Thin SignalR push helper for ACL + role-grant invalidation — slice 2 of task #196.
|
|
/// Lets the Admin services + razor pages invalidate connected peers' views without each
|
|
/// one having to know the hub wiring. Two message kinds: <c>NodeAclChanged</c> (cluster-scoped)
|
|
/// and <c>RoleGrantsChanged</c> (fleet-wide — role mappings cross cluster boundaries).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Intentionally fire-and-forget — a failed hub send doesn't rollback the DB write that
|
|
/// triggered it. Worst-case an operator sees stale data until their next poll or manual
|
|
/// refresh; better than a transient hub blip blocking the authoritative write path.
|
|
/// </remarks>
|
|
public sealed class AclChangeNotifier(IHubContext<FleetStatusHub> fleetHub, ILogger<AclChangeNotifier> logger)
|
|
{
|
|
public async Task NotifyNodeAclChangedAsync(string clusterId, long generationId, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var msg = new NodeAclChangedMessage(ClusterId: clusterId, GenerationId: generationId, ObservedAtUtc: DateTime.UtcNow);
|
|
await fleetHub.Clients.Group(FleetStatusHub.GroupName(clusterId))
|
|
.SendAsync("NodeAclChanged", msg, ct).ConfigureAwait(false);
|
|
}
|
|
catch (Exception ex) when (ex is not OperationCanceledException)
|
|
{
|
|
logger.LogWarning(ex, "NodeAclChanged push failed for cluster {ClusterId} gen {GenerationId}", clusterId, generationId);
|
|
}
|
|
}
|
|
|
|
public async Task NotifyRoleGrantsChangedAsync(CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var msg = new RoleGrantsChangedMessage(ObservedAtUtc: DateTime.UtcNow);
|
|
await fleetHub.Clients.Group(FleetStatusHub.FleetGroup)
|
|
.SendAsync("RoleGrantsChanged", msg, ct).ConfigureAwait(false);
|
|
}
|
|
catch (Exception ex) when (ex is not OperationCanceledException)
|
|
{
|
|
logger.LogWarning(ex, "RoleGrantsChanged push failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
public sealed record NodeAclChangedMessage(string ClusterId, long GenerationId, DateTime ObservedAtUtc);
|
|
public sealed record RoleGrantsChangedMessage(DateTime ObservedAtUtc);
|