using Microsoft.Extensions.Logging; using MxGateway.Client; using MxGateway.Contracts.Proto; namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Runtime; /// /// Production backed by the session-less /// MxGatewayClient.AcknowledgeAlarmAsync RPC. The updated gateway routes /// acknowledgement through its always-on central alarm monitor, so no worker /// session is involved — the driver supplies only the alarm reference, comment, /// and operator principal. /// /// /// A non-OK means the gateway never reached MXAccess /// (transport / dispatch failure) and is surfaced as a thrown exception. A non-zero /// native ack return code (hresult) means MXAccess itself rejected the ack; /// that is logged as a warning rather than thrown so a transient MXAccess hiccup /// doesn't block the operator workflow — the operator can retry. /// internal sealed class GatewayGalaxyAlarmAcknowledger : IGalaxyAlarmAcknowledger { private readonly MxGatewayClient _client; private readonly ILogger _logger; public GatewayGalaxyAlarmAcknowledger(MxGatewayClient client, ILogger logger) { _client = client ?? throw new ArgumentNullException(nameof(client)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task AcknowledgeAsync( string alarmFullReference, string comment, string operatorUser, CancellationToken cancellationToken) { ArgumentException.ThrowIfNullOrEmpty(alarmFullReference); var reply = await _client.AcknowledgeAlarmAsync( new AcknowledgeAlarmRequest { ClientCorrelationId = Guid.NewGuid().ToString("N"), AlarmFullReference = alarmFullReference, Comment = comment ?? string.Empty, OperatorUser = operatorUser ?? string.Empty, }, cancellationToken).ConfigureAwait(false); // Protocol status — the gateway failed before MXAccess saw the ack. This is a // hard failure: the operator's request was not delivered at all. if (reply.ProtocolStatus is { } proto && proto.Code != ProtocolStatusCode.Ok) { throw new InvalidOperationException( $"Galaxy AcknowledgeAlarm for '{alarmFullReference}' failed at the gateway: " + $"{proto.Code} {proto.Message}"); } // hresult is the authoritative native ack return code (0 = success). It is // absent only on a worker protocol violation; with an OK protocol status a // missing value is treated as success. if (reply.HasHresult && reply.Hresult != 0) { _logger.LogWarning( "Galaxy AcknowledgeAlarm for {AlarmRef} returned native ack failure code {Hresult}.", alarmFullReference, reply.Hresult); } } }